19f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
39f62ea84SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
49f62ea84SAndrew Rist * or more contributor license agreements. See the NOTICE file
59f62ea84SAndrew Rist * distributed with this work for additional information
69f62ea84SAndrew Rist * regarding copyright ownership. The ASF licenses this file
79f62ea84SAndrew Rist * to you under the Apache License, Version 2.0 (the
89f62ea84SAndrew Rist * "License"); you may not use this file except in compliance
99f62ea84SAndrew Rist * with the License. You may obtain a copy of the License at
109f62ea84SAndrew Rist *
119f62ea84SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
129f62ea84SAndrew Rist *
139f62ea84SAndrew Rist * Unless required by applicable law or agreed to in writing,
149f62ea84SAndrew Rist * software distributed under the License is distributed on an
159f62ea84SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f62ea84SAndrew Rist * KIND, either express or implied. See the License for the
179f62ea84SAndrew Rist * specific language governing permissions and limitations
189f62ea84SAndrew Rist * under the License.
199f62ea84SAndrew Rist *
209f62ea84SAndrew Rist *************************************************************/
219f62ea84SAndrew Rist
229f62ea84SAndrew Rist
23cdf0e10cSrcweir
24fc9fd3f1SPedro Giffuni #define INCL_GPI
25fc9fd3f1SPedro Giffuni #define INCL_DOS
26fc9fd3f1SPedro Giffuni #include <svpm.h>
27cdf0e10cSrcweir
28fc9fd3f1SPedro Giffuni #include "tools/svwin.h"
29fc9fd3f1SPedro Giffuni
30fc9fd3f1SPedro Giffuni #include "vcl/svapp.hxx"
31fc9fd3f1SPedro Giffuni
32fc9fd3f1SPedro Giffuni #include "os2/salgdi.h"
33fc9fd3f1SPedro Giffuni #include "os2/saldata.hxx"
34fc9fd3f1SPedro Giffuni
35fc9fd3f1SPedro Giffuni // for GetMirroredChar
36fc9fd3f1SPedro Giffuni #include "sft.hxx"
37fc9fd3f1SPedro Giffuni #include "sallayout.hxx"
38fc9fd3f1SPedro Giffuni
39fc9fd3f1SPedro Giffuni #include "rtl/ustring.hxx"
40fc9fd3f1SPedro Giffuni #include "osl/module.h"
41fc9fd3f1SPedro Giffuni #include "sallayout.hxx"
42cdf0e10cSrcweir
43cdf0e10cSrcweir #ifndef __H_FT2LIB
44fc9fd3f1SPedro Giffuni #include <os2/wingdi.h>
45cdf0e10cSrcweir #include <ft2lib.h>
46cdf0e10cSrcweir #endif
47cdf0e10cSrcweir
48cdf0e10cSrcweir #include <cstdio>
49cdf0e10cSrcweir #include <malloc.h>
50cdf0e10cSrcweir
51cdf0e10cSrcweir #ifdef GCP_KERN_HACK
52cdf0e10cSrcweir #include <algorithm>
53cdf0e10cSrcweir #endif // GCP_KERN_HACK
54cdf0e10cSrcweir
55cdf0e10cSrcweir #include <hash_map>
56cdf0e10cSrcweir typedef std::hash_map<int,int> IntMap;
57cdf0e10cSrcweir
58cdf0e10cSrcweir #define DROPPED_OUTGLYPH 0xFFFF
59cdf0e10cSrcweir
60cdf0e10cSrcweir using namespace rtl;
61cdf0e10cSrcweir
62cdf0e10cSrcweir // =======================================================================
63cdf0e10cSrcweir
64cdf0e10cSrcweir // OS/2 specific physical font instance
65cdf0e10cSrcweir class ImplOs2FontEntry : public ImplFontEntry
66cdf0e10cSrcweir {
67cdf0e10cSrcweir public:
68cdf0e10cSrcweir ImplOs2FontEntry( ImplFontSelectData& );
69cdf0e10cSrcweir ~ImplOs2FontEntry();
70cdf0e10cSrcweir
71cdf0e10cSrcweir private:
72cdf0e10cSrcweir // TODO: also add HFONT??? Watch out for issues with too many active fonts...
73cdf0e10cSrcweir
74cdf0e10cSrcweir #ifdef GCP_KERN_HACK
75cdf0e10cSrcweir public:
76cdf0e10cSrcweir bool HasKernData() const;
77cdf0e10cSrcweir void SetKernData( int, const KERNINGPAIRS* );
78cdf0e10cSrcweir int GetKerning( sal_Unicode, sal_Unicode ) const;
79cdf0e10cSrcweir private:
80cdf0e10cSrcweir KERNINGPAIRS* mpKerningPairs;
81cdf0e10cSrcweir int mnKerningPairs;
82cdf0e10cSrcweir #endif // GCP_KERN_HACK
83cdf0e10cSrcweir
84cdf0e10cSrcweir public:
85cdf0e10cSrcweir int GetCachedGlyphWidth( int nCharCode ) const;
86cdf0e10cSrcweir void CacheGlyphWidth( int nCharCode, int nCharWidth );
87cdf0e10cSrcweir private:
88cdf0e10cSrcweir IntMap maWidthMap;
89cdf0e10cSrcweir };
90cdf0e10cSrcweir
91cdf0e10cSrcweir // -----------------------------------------------------------------------
92cdf0e10cSrcweir
CacheGlyphWidth(int nCharCode,int nCharWidth)93cdf0e10cSrcweir inline void ImplOs2FontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth )
94cdf0e10cSrcweir {
95cdf0e10cSrcweir maWidthMap[ nCharCode ] = nCharWidth;
96cdf0e10cSrcweir }
97cdf0e10cSrcweir
GetCachedGlyphWidth(int nCharCode) const98cdf0e10cSrcweir inline int ImplOs2FontEntry::GetCachedGlyphWidth( int nCharCode ) const
99cdf0e10cSrcweir {
100cdf0e10cSrcweir IntMap::const_iterator it = maWidthMap.find( nCharCode );
101cdf0e10cSrcweir if( it == maWidthMap.end() )
102cdf0e10cSrcweir return -1;
103cdf0e10cSrcweir return it->second;
104cdf0e10cSrcweir }
105cdf0e10cSrcweir
106cdf0e10cSrcweir // =======================================================================
107cdf0e10cSrcweir
108cdf0e10cSrcweir class Os2Layout : public SalLayout
109cdf0e10cSrcweir {
110cdf0e10cSrcweir public:
111cdf0e10cSrcweir Os2Layout( HDC, const ImplOs2FontData&, ImplOs2FontEntry& );
112cdf0e10cSrcweir virtual void InitFont() const;
SetFontScale(float f)113cdf0e10cSrcweir void SetFontScale( float f ) { mfFontScale = f; }
GetFontScale() const114cdf0e10cSrcweir float GetFontScale() const { return mfFontScale; }
115cdf0e10cSrcweir
116cdf0e10cSrcweir protected:
117cdf0e10cSrcweir HPS mhPS; // OS2 device handle
118cdf0e10cSrcweir FATTRS mhFont;
119cdf0e10cSrcweir int mnBaseAdv; // x-offset relative to Layout origin
120cdf0e10cSrcweir float mfFontScale; // allows metrics emulation of huge font sizes
121cdf0e10cSrcweir
122cdf0e10cSrcweir const ImplOs2FontData& mrOs2FontData;
123cdf0e10cSrcweir ImplOs2FontEntry& mrOs2FontEntry;
124cdf0e10cSrcweir };
125cdf0e10cSrcweir
126cdf0e10cSrcweir // =======================================================================
127cdf0e10cSrcweir
128cdf0e10cSrcweir class Os2SalLayout : public Os2Layout
129cdf0e10cSrcweir {
130cdf0e10cSrcweir public:
131fc9fd3f1SPedro Giffuni Os2SalLayout( HPS, PM_BYTE nCharSet, const ImplOs2FontData&, ImplOs2FontEntry& );
132cdf0e10cSrcweir virtual ~Os2SalLayout();
133cdf0e10cSrcweir
134cdf0e10cSrcweir virtual bool LayoutText( ImplLayoutArgs& );
135cdf0e10cSrcweir virtual void AdjustLayout( ImplLayoutArgs& );
136cdf0e10cSrcweir virtual void DrawText( SalGraphics& ) const;
137cdf0e10cSrcweir
138cdf0e10cSrcweir virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
139cdf0e10cSrcweir sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
140cdf0e10cSrcweir
141cdf0e10cSrcweir virtual long FillDXArray( long* pDXArray ) const;
142cdf0e10cSrcweir virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
143cdf0e10cSrcweir virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
144cdf0e10cSrcweir
145cdf0e10cSrcweir // for glyph+font+script fallback
146cdf0e10cSrcweir virtual void MoveGlyph( int nStart, long nNewXPos );
147cdf0e10cSrcweir virtual void DropGlyph( int nStart );
148cdf0e10cSrcweir virtual void Simplify( bool bIsBase );
149cdf0e10cSrcweir
150cdf0e10cSrcweir protected:
151cdf0e10cSrcweir void Justify( long nNewWidth );
152cdf0e10cSrcweir void ApplyDXArray( const ImplLayoutArgs& );
153cdf0e10cSrcweir
154cdf0e10cSrcweir protected:
155cdf0e10cSrcweir
156cdf0e10cSrcweir private:
157cdf0e10cSrcweir int mnGlyphCount;
158cdf0e10cSrcweir int mnCharCount;
159cdf0e10cSrcweir sal_Unicode* mpOutGlyphs;
160cdf0e10cSrcweir int* mpGlyphAdvances; // if possible this is shared with mpGlyphAdvances[]
161cdf0e10cSrcweir int* mpGlyphOrigAdvs;
162cdf0e10cSrcweir int* mpCharWidths; // map rel char pos to char width
163cdf0e10cSrcweir int* mpChars2Glyphs; // map rel char pos to abs glyph pos
164cdf0e10cSrcweir int* mpGlyphs2Chars; // map abs glyph pos to abs char pos
165cdf0e10cSrcweir bool* mpGlyphRTLFlags; // BiDi status for glyphs: true=>RTL
166cdf0e10cSrcweir mutable long mnWidth;
167cdf0e10cSrcweir bool mbDisableGlyphs;
168cdf0e10cSrcweir
169cdf0e10cSrcweir int mnNotdefWidth;
170fc9fd3f1SPedro Giffuni PM_BYTE mnCharSet;
171cdf0e10cSrcweir
172cdf0e10cSrcweir };
173cdf0e10cSrcweir
174cdf0e10cSrcweir // =======================================================================
175cdf0e10cSrcweir
Os2Layout(HPS hPS,const ImplOs2FontData & rWFD,ImplOs2FontEntry & rWFE)176cdf0e10cSrcweir Os2Layout::Os2Layout( HPS hPS, const ImplOs2FontData& rWFD, ImplOs2FontEntry& rWFE )
177cdf0e10cSrcweir : mhPS( hPS ),
178cdf0e10cSrcweir mnBaseAdv( 0 ),
179cdf0e10cSrcweir mfFontScale( 1.0 ),
180cdf0e10cSrcweir mrOs2FontData( rWFD ),
181cdf0e10cSrcweir mrOs2FontEntry( rWFE )
182cdf0e10cSrcweir {
183fc9fd3f1SPedro Giffuni sal_Bool fSuccess;
184cdf0e10cSrcweir fSuccess = Ft2QueryLogicalFont( mhPS, LCID_BASE, NULL, &mhFont, sizeof(FATTRS));
185cdf0e10cSrcweir }
186cdf0e10cSrcweir
187cdf0e10cSrcweir // -----------------------------------------------------------------------
188cdf0e10cSrcweir
InitFont() const189cdf0e10cSrcweir void Os2Layout::InitFont() const
190cdf0e10cSrcweir {
191cdf0e10cSrcweir // select fallback level 0 font
192cdf0e10cSrcweir APIRET rc = Ft2CreateLogFont( mhPS, NULL, LCID_BASE, (PFATTRS)&mhFont);
193cdf0e10cSrcweir }
194cdf0e10cSrcweir
195cdf0e10cSrcweir // =======================================================================
196cdf0e10cSrcweir
Os2SalLayout(HPS hPS,PM_BYTE nCharSet,const ImplOs2FontData & rOs2FontData,ImplOs2FontEntry & rOs2FontEntry)197fc9fd3f1SPedro Giffuni Os2SalLayout::Os2SalLayout( HPS hPS, PM_BYTE nCharSet,
198cdf0e10cSrcweir const ImplOs2FontData& rOs2FontData, ImplOs2FontEntry& rOs2FontEntry )
199cdf0e10cSrcweir : Os2Layout( hPS, rOs2FontData, rOs2FontEntry ),
200cdf0e10cSrcweir mnGlyphCount( 0 ),
201cdf0e10cSrcweir mnCharCount( 0 ),
202cdf0e10cSrcweir mpOutGlyphs( NULL ),
203cdf0e10cSrcweir mpGlyphAdvances( NULL ),
204cdf0e10cSrcweir mpGlyphOrigAdvs( NULL ),
205cdf0e10cSrcweir mpCharWidths( NULL ),
206cdf0e10cSrcweir mpChars2Glyphs( NULL ),
207cdf0e10cSrcweir mpGlyphs2Chars( NULL ),
208cdf0e10cSrcweir mpGlyphRTLFlags( NULL ),
209cdf0e10cSrcweir mnWidth( 0 ),
210cdf0e10cSrcweir mnNotdefWidth( -1 ),
211cdf0e10cSrcweir mnCharSet( nCharSet ),
212cdf0e10cSrcweir mbDisableGlyphs( false )
213cdf0e10cSrcweir {
214cdf0e10cSrcweir mbDisableGlyphs = true;
215cdf0e10cSrcweir }
216cdf0e10cSrcweir
217cdf0e10cSrcweir // -----------------------------------------------------------------------
218cdf0e10cSrcweir
~Os2SalLayout()219cdf0e10cSrcweir Os2SalLayout::~Os2SalLayout()
220cdf0e10cSrcweir {
221cdf0e10cSrcweir delete[] mpGlyphRTLFlags;
222cdf0e10cSrcweir delete[] mpGlyphs2Chars;
223cdf0e10cSrcweir delete[] mpChars2Glyphs;
224cdf0e10cSrcweir if( mpCharWidths != mpGlyphAdvances )
225cdf0e10cSrcweir delete[] mpCharWidths;
226cdf0e10cSrcweir delete[] mpGlyphOrigAdvs;
227cdf0e10cSrcweir delete[] mpGlyphAdvances;
228cdf0e10cSrcweir delete[] mpOutGlyphs;
229cdf0e10cSrcweir }
230cdf0e10cSrcweir
231cdf0e10cSrcweir // -----------------------------------------------------------------------
232cdf0e10cSrcweir
LayoutText(ImplLayoutArgs & rArgs)233cdf0e10cSrcweir bool Os2SalLayout::LayoutText( ImplLayoutArgs& rArgs )
234cdf0e10cSrcweir {
235cdf0e10cSrcweir // prepare layout
236cdf0e10cSrcweir // TODO: fix case when recyclying old Os2SalLayout object
237cdf0e10cSrcweir mbDisableGlyphs |= ((rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) != 0);
238cdf0e10cSrcweir mnCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
239cdf0e10cSrcweir
240cdf0e10cSrcweir if( !mbDisableGlyphs )
241cdf0e10cSrcweir {
242cdf0e10cSrcweir // Win32 glyph APIs have serious problems with vertical layout
243cdf0e10cSrcweir // => workaround is to use the unicode methods then
244cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_VERTICAL )
245cdf0e10cSrcweir mbDisableGlyphs = true;
246cdf0e10cSrcweir else
247cdf0e10cSrcweir // use cached value from font face
248cdf0e10cSrcweir mbDisableGlyphs = mrOs2FontData.IsGlyphApiDisabled();
249cdf0e10cSrcweir }
250cdf0e10cSrcweir
251cdf0e10cSrcweir // TODO: use a cached value for bDisableAsianKern from upper layers
252cdf0e10cSrcweir #if 0
253cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
254cdf0e10cSrcweir {
255cdf0e10cSrcweir TEXTMETRICA aTextMetricA;
256cdf0e10cSrcweir if( ::GetTextMetricsA( mhDC, &aTextMetricA )
257cdf0e10cSrcweir && !(aTextMetricA.tmPitchAndFamily & TMPF_FIXED_PITCH) )
258cdf0e10cSrcweir rArgs.mnFlags &= ~SAL_LAYOUT_KERNING_ASIAN;
259cdf0e10cSrcweir }
260cdf0e10cSrcweir #endif
261cdf0e10cSrcweir
262cdf0e10cSrcweir // layout text
263cdf0e10cSrcweir int i, j;
264cdf0e10cSrcweir
265cdf0e10cSrcweir mnGlyphCount = 0;
266cdf0e10cSrcweir bool bVertical = (rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0;
267cdf0e10cSrcweir
268cdf0e10cSrcweir // count the number of chars to process if no RTL run
269cdf0e10cSrcweir rArgs.ResetPos();
270cdf0e10cSrcweir bool bHasRTL = false;
271cdf0e10cSrcweir while( rArgs.GetNextRun( &i, &j, &bHasRTL ) && !bHasRTL )
272cdf0e10cSrcweir mnGlyphCount += j - i;
273cdf0e10cSrcweir
274cdf0e10cSrcweir // if there are RTL runs we need room to remember individual BiDi flags
275cdf0e10cSrcweir if( bHasRTL )
276cdf0e10cSrcweir {
277cdf0e10cSrcweir mpGlyphRTLFlags = new bool[ mnCharCount ];
278cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i )
279cdf0e10cSrcweir mpGlyphRTLFlags[i] = false;
280cdf0e10cSrcweir }
281cdf0e10cSrcweir
282cdf0e10cSrcweir // rewrite the logical string if needed to prepare for the API calls
283cdf0e10cSrcweir const sal_Unicode* pBidiStr = rArgs.mpStr + rArgs.mnMinCharPos;
284cdf0e10cSrcweir if( (mnGlyphCount != mnCharCount) || bVertical )
285cdf0e10cSrcweir {
286cdf0e10cSrcweir // we need to rewrite the pBidiStr when any of
287cdf0e10cSrcweir // - BiDirectional layout
288cdf0e10cSrcweir // - vertical layout
289cdf0e10cSrcweir // - partial runs (e.g. with control chars or for glyph fallback)
290cdf0e10cSrcweir // are involved
291cdf0e10cSrcweir sal_Unicode* pRewrittenStr = (sal_Unicode*)alloca( mnCharCount * sizeof(sal_Unicode) );
292cdf0e10cSrcweir pBidiStr = pRewrittenStr;
293cdf0e10cSrcweir
294cdf0e10cSrcweir // note: glyph to char mapping is relative to first character
295cdf0e10cSrcweir mpChars2Glyphs = new int[ mnCharCount ];
296cdf0e10cSrcweir mpGlyphs2Chars = new int[ mnCharCount ];
297cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i )
298cdf0e10cSrcweir mpChars2Glyphs[i] = mpGlyphs2Chars[i] = -1;
299cdf0e10cSrcweir
300cdf0e10cSrcweir mnGlyphCount = 0;
301cdf0e10cSrcweir rArgs.ResetPos();
302cdf0e10cSrcweir bool bIsRTL = false;
303cdf0e10cSrcweir while( rArgs.GetNextRun( &i, &j, &bIsRTL ) )
304cdf0e10cSrcweir {
305cdf0e10cSrcweir do
306cdf0e10cSrcweir {
307cdf0e10cSrcweir // get the next leftmost character in this run
308cdf0e10cSrcweir int nCharPos = bIsRTL ? --j : i++;
309cdf0e10cSrcweir sal_Unicode cChar = rArgs.mpStr[ nCharPos ];
310cdf0e10cSrcweir
311cdf0e10cSrcweir // in the RTL case mirror the character and remember its RTL status
312cdf0e10cSrcweir if( bIsRTL )
313cdf0e10cSrcweir {
314cdf0e10cSrcweir cChar = ::GetMirroredChar( cChar );
315cdf0e10cSrcweir mpGlyphRTLFlags[ mnGlyphCount ] = true;
316cdf0e10cSrcweir }
317cdf0e10cSrcweir
318cdf0e10cSrcweir // for vertical writing use vertical alternatives
319cdf0e10cSrcweir if( bVertical )
320cdf0e10cSrcweir {
321cdf0e10cSrcweir sal_Unicode cVert = ::GetVerticalChar( cChar );
322cdf0e10cSrcweir if( cVert )
323cdf0e10cSrcweir cChar = cVert;
324cdf0e10cSrcweir }
325cdf0e10cSrcweir
326cdf0e10cSrcweir // rewrite the original string
327cdf0e10cSrcweir // update the mappings between original and rewritten string
328cdf0e10cSrcweir pRewrittenStr[ mnGlyphCount ] = cChar;
329cdf0e10cSrcweir mpGlyphs2Chars[ mnGlyphCount ] = nCharPos;
330cdf0e10cSrcweir mpChars2Glyphs[ nCharPos - rArgs.mnMinCharPos ] = mnGlyphCount;
331cdf0e10cSrcweir ++mnGlyphCount;
332cdf0e10cSrcweir } while( i < j );
333cdf0e10cSrcweir }
334cdf0e10cSrcweir }
335cdf0e10cSrcweir
336cdf0e10cSrcweir mpOutGlyphs = new sal_Unicode[ mnGlyphCount ];
337cdf0e10cSrcweir mpGlyphAdvances = new int[ mnGlyphCount ];
338cdf0e10cSrcweir
339cdf0e10cSrcweir if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_PAIRS | SAL_LAYOUT_KERNING_ASIAN) )
340cdf0e10cSrcweir mpGlyphOrigAdvs = new int[ mnGlyphCount ];
341cdf0e10cSrcweir
342cdf0e10cSrcweir #ifndef GCP_KERN_HACK
343cdf0e10cSrcweir DWORD nGcpOption = 0;
344cdf0e10cSrcweir // enable kerning if requested
345cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
346cdf0e10cSrcweir nGcpOption |= GCP_USEKERNING;
347cdf0e10cSrcweir #endif // GCP_KERN_HACK
348cdf0e10cSrcweir
349cdf0e10cSrcweir LONG lLcid = Ft2QueryCharSet( mhPS);
350cdf0e10cSrcweir
351cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
352cdf0e10cSrcweir mpOutGlyphs[i] = pBidiStr[ i ];
353cdf0e10cSrcweir mnWidth = 0;
354cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
355cdf0e10cSrcweir {
356cdf0e10cSrcweir const sal_Unicode* pCodes = &pBidiStr[i];
357cdf0e10cSrcweir // check for surrogate pairs
358cdf0e10cSrcweir if( (pCodes[0] & 0xFC00) == 0xDC00 )
359cdf0e10cSrcweir continue;
360cdf0e10cSrcweir bool bSurrogate = ((pCodes[0] & 0xFC00) == 0xD800);
361cdf0e10cSrcweir
362cdf0e10cSrcweir // get the width of the corresponding code point
363cdf0e10cSrcweir int nCharCode = pCodes[0];
364cdf0e10cSrcweir if( bSurrogate )
365cdf0e10cSrcweir nCharCode = 0x10000 + ((pCodes[0] & 0x03FF) << 10) + (pCodes[1] & 0x03FF);
366cdf0e10cSrcweir int nGlyphWidth = mrOs2FontEntry.GetCachedGlyphWidth( nCharCode );
367cdf0e10cSrcweir if( nGlyphWidth == -1 )
368cdf0e10cSrcweir {
369cdf0e10cSrcweir if (!Ft2QueryStringWidthW( mhPS, (LPWSTR)&pCodes[0], 1, (LONG*)&nGlyphWidth))
370cdf0e10cSrcweir nGlyphWidth = 0;
371cdf0e10cSrcweir mrOs2FontEntry.CacheGlyphWidth( nCharCode, nGlyphWidth );
372cdf0e10cSrcweir }
373cdf0e10cSrcweir mpGlyphAdvances[ i ] = nGlyphWidth;
374cdf0e10cSrcweir mnWidth += nGlyphWidth;
375cdf0e10cSrcweir
376cdf0e10cSrcweir // remaining codes of surrogate pair get a zero width
377cdf0e10cSrcweir if( bSurrogate )
378cdf0e10cSrcweir mpGlyphAdvances[ i+1 ] = 0;
379cdf0e10cSrcweir
380cdf0e10cSrcweir // check with the font face if glyph fallback is needed
381cdf0e10cSrcweir if( mrOs2FontData.HasChar( nCharCode ) )
382cdf0e10cSrcweir continue;
383cdf0e10cSrcweir // Type1 charmaps are not complete (or buggy), use FT2 to check again
384cdf0e10cSrcweir if (Ft2FontSupportsUnicodeChar( mhPS, lLcid, TRUE, nCharCode))
385cdf0e10cSrcweir continue;
386cdf0e10cSrcweir
387cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>0
388cdf0e10cSrcweir debug_printf("Os2SalLayout::LayoutText font does not support unicode char\n");
389cdf0e10cSrcweir #endif
390cdf0e10cSrcweir // request glyph fallback at this position in the string
391cdf0e10cSrcweir bool bRTL = mpGlyphRTLFlags ? mpGlyphRTLFlags[i] : false;
392cdf0e10cSrcweir int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[i]: i + rArgs.mnMinCharPos;
393cdf0e10cSrcweir rArgs.NeedFallback( nCharPos, bRTL );
394cdf0e10cSrcweir if( bSurrogate )
395cdf0e10cSrcweir rArgs.NeedFallback( nCharPos+1, bRTL );
396cdf0e10cSrcweir
397cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
398cdf0e10cSrcweir {
399cdf0e10cSrcweir // when we already are layouting for glyph fallback
400cdf0e10cSrcweir // then a new unresolved glyph is not interesting
401cdf0e10cSrcweir mnNotdefWidth = 0;
402cdf0e10cSrcweir mpOutGlyphs[i] = DROPPED_OUTGLYPH;
403cdf0e10cSrcweir if( mbDisableGlyphs && bSurrogate )
404cdf0e10cSrcweir mpOutGlyphs[i+1] = DROPPED_OUTGLYPH;
405cdf0e10cSrcweir }
406cdf0e10cSrcweir else
407cdf0e10cSrcweir {
408cdf0e10cSrcweir if( mnNotdefWidth < 0 )
409cdf0e10cSrcweir {
410cdf0e10cSrcweir // get the width of the NotDef glyph
411cdf0e10cSrcweir LONG aExtent;
412cdf0e10cSrcweir mnNotdefWidth = 0;
413cdf0e10cSrcweir if (Ft2QueryStringWidthW( mhPS, (LPWSTR)&rArgs.mpStr[ nCharPos ], 1, &aExtent))
414cdf0e10cSrcweir mnNotdefWidth = aExtent;
415cdf0e10cSrcweir }
416cdf0e10cSrcweir // use a better NotDef glyph
417cdf0e10cSrcweir if( !mbDisableGlyphs )
418cdf0e10cSrcweir mpOutGlyphs[i] = 0;
419cdf0e10cSrcweir }
420cdf0e10cSrcweir
421cdf0e10cSrcweir // replace the current glyph with the NotDef glyph
422cdf0e10cSrcweir mnWidth += mnNotdefWidth - mpGlyphAdvances[i];
423cdf0e10cSrcweir mpGlyphAdvances[i] = mnNotdefWidth;
424cdf0e10cSrcweir if( mpGlyphOrigAdvs )
425cdf0e10cSrcweir mpGlyphOrigAdvs[i] = mnNotdefWidth;
426cdf0e10cSrcweir }
427cdf0e10cSrcweir
428cdf0e10cSrcweir #ifdef GCP_KERN_HACK
429cdf0e10cSrcweir // apply kerning if the layout engine has not yet done it
430cdf0e10cSrcweir if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_ASIAN|SAL_LAYOUT_KERNING_PAIRS) )
431cdf0e10cSrcweir {
432cdf0e10cSrcweir #else // GCP_KERN_HACK
433cdf0e10cSrcweir // apply just asian kerning
434cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
435cdf0e10cSrcweir {
436cdf0e10cSrcweir if( !(rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) )
437cdf0e10cSrcweir #endif // GCP_KERN_HACK
438cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
439cdf0e10cSrcweir mpGlyphOrigAdvs[i] = mpGlyphAdvances[i];
440cdf0e10cSrcweir
441cdf0e10cSrcweir // #99658# also apply asian kerning on the substring border
442cdf0e10cSrcweir int nLen = mnGlyphCount;
443cdf0e10cSrcweir if( rArgs.mnMinCharPos + nLen < rArgs.mnLength )
444cdf0e10cSrcweir ++nLen;
445cdf0e10cSrcweir for( i = 1; i < nLen; ++i )
446cdf0e10cSrcweir {
447cdf0e10cSrcweir #ifdef GCP_KERN_HACK
448cdf0e10cSrcweir if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
449cdf0e10cSrcweir {
450cdf0e10cSrcweir int nKernAmount = mrOs2FontEntry.GetKerning( pBidiStr[i-1], pBidiStr[i] );
451cdf0e10cSrcweir mpGlyphAdvances[ i-1 ] += nKernAmount;
452cdf0e10cSrcweir mnWidth += nKernAmount;
453cdf0e10cSrcweir }
454cdf0e10cSrcweir else if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
455cdf0e10cSrcweir #endif // GCP_KERN_HACK
456cdf0e10cSrcweir
457cdf0e10cSrcweir if( (0x3000 == (0xFF00 & pBidiStr[i-1]))
458cdf0e10cSrcweir && (0x3000 == (0xFF00 & pBidiStr[i])) )
459cdf0e10cSrcweir {
460cdf0e10cSrcweir long nKernFirst = +CalcAsianKerning( pBidiStr[i-1], true, bVertical );
461cdf0e10cSrcweir long nKernNext = -CalcAsianKerning( pBidiStr[i], false, bVertical );
462cdf0e10cSrcweir
463cdf0e10cSrcweir long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext;
464cdf0e10cSrcweir if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 )
465cdf0e10cSrcweir {
466cdf0e10cSrcweir nDelta = (nDelta * mpGlyphAdvances[i-1] + 2) / 4;
467cdf0e10cSrcweir mpGlyphAdvances[i-1] += nDelta;
468cdf0e10cSrcweir mnWidth += nDelta;
469cdf0e10cSrcweir }
470cdf0e10cSrcweir }
471cdf0e10cSrcweir }
472cdf0e10cSrcweir }
473cdf0e10cSrcweir
474cdf0e10cSrcweir // calculate virtual char widths
475cdf0e10cSrcweir if( !mpGlyphs2Chars )
476cdf0e10cSrcweir mpCharWidths = mpGlyphAdvances;
477cdf0e10cSrcweir else
478cdf0e10cSrcweir {
479cdf0e10cSrcweir mpCharWidths = new int[ mnCharCount ];
480cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i )
481cdf0e10cSrcweir mpCharWidths[ i ] = 0;
482cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
483cdf0e10cSrcweir {
484cdf0e10cSrcweir int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
485cdf0e10cSrcweir if( j >= 0 )
486cdf0e10cSrcweir mpCharWidths[ j ] += mpGlyphAdvances[ i ];
487cdf0e10cSrcweir }
488cdf0e10cSrcweir }
489cdf0e10cSrcweir
490cdf0e10cSrcweir // scale layout metrics if needed
491cdf0e10cSrcweir if( mfFontScale != 1.0 )
492cdf0e10cSrcweir {
493cdf0e10cSrcweir mnWidth *= mfFontScale;
494cdf0e10cSrcweir mnBaseAdv *= mfFontScale;
495cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i )
496cdf0e10cSrcweir mpCharWidths[ i ] *= mfFontScale;
497cdf0e10cSrcweir if( mpGlyphAdvances != mpCharWidths )
498cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
499cdf0e10cSrcweir mpGlyphAdvances[ i ] *= mfFontScale;
500cdf0e10cSrcweir if( mpGlyphOrigAdvs && (mpGlyphOrigAdvs != mpGlyphAdvances) )
501cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
502cdf0e10cSrcweir mpGlyphOrigAdvs[ i ] *= mfFontScale;
503cdf0e10cSrcweir }
504cdf0e10cSrcweir
505cdf0e10cSrcweir return true;
506cdf0e10cSrcweir }
507cdf0e10cSrcweir
508cdf0e10cSrcweir // -----------------------------------------------------------------------
509cdf0e10cSrcweir
510*248a599fSHerbert Dürr int Os2SalLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIds, Point& rPos, int& nStart,
511cdf0e10cSrcweir sal_Int32* pGlyphAdvances, int* pCharIndexes ) const
512cdf0e10cSrcweir {
513cdf0e10cSrcweir // return zero if no more glyph found
514cdf0e10cSrcweir if( nStart >= mnGlyphCount )
515cdf0e10cSrcweir return 0;
516cdf0e10cSrcweir
517cdf0e10cSrcweir // calculate glyph position relative to layout base
518cdf0e10cSrcweir // TODO: avoid for nStart!=0 case by reusing rPos
519cdf0e10cSrcweir long nXOffset = mnBaseAdv;
520cdf0e10cSrcweir for( int i = 0; i < nStart; ++i )
521cdf0e10cSrcweir nXOffset += mpGlyphAdvances[ i ];
522cdf0e10cSrcweir
523cdf0e10cSrcweir // calculate absolute position in pixel units
524cdf0e10cSrcweir Point aRelativePos( nXOffset, 0 );
525cdf0e10cSrcweir rPos = GetDrawPosition( aRelativePos );
526cdf0e10cSrcweir
527cdf0e10cSrcweir int nCount = 0;
528cdf0e10cSrcweir while( nCount < nLen )
529cdf0e10cSrcweir {
530*248a599fSHerbert Dürr // update return values {aGlyphId,nCharPos,nGlyphAdvance}
531*248a599fSHerbert Dürr sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
532cdf0e10cSrcweir if( mbDisableGlyphs )
533cdf0e10cSrcweir {
534cdf0e10cSrcweir if( mnLayoutFlags & SAL_LAYOUT_VERTICAL )
535cdf0e10cSrcweir {
536*248a599fSHerbert Dürr sal_Unicode cChar = (sal_Unicode)(aGlyphId & GF_IDXMASK);
537cdf0e10cSrcweir #ifdef GNG_VERT_HACK
538cdf0e10cSrcweir if( mrOs2FontData.HasGSUBstitutions( mhPS )
539cdf0e10cSrcweir && mrOs2FontData.IsGSUBstituted( cChar ) )
540*248a599fSHerbert Dürr aGlyphId |= GF_ROTL | GF_GSUB;
541cdf0e10cSrcweir else
542cdf0e10cSrcweir #endif // GNG_VERT_HACK
543cdf0e10cSrcweir {
544*248a599fSHerbert Dürr aGlyphId |= GetVerticalFlags( cChar );
545*248a599fSHerbert Dürr if( !(aGlyphId & GF_ROTMASK) )
546*248a599fSHerbert Dürr aGlyphId |= GF_VERT;
547cdf0e10cSrcweir }
548cdf0e10cSrcweir }
549*248a599fSHerbert Dürr aGlyphId |= GF_ISCHAR;
550cdf0e10cSrcweir }
551cdf0e10cSrcweir ++nCount;
552*248a599fSHerbert Dürr *(pGlyphIds++) = aGlyphId;
553cdf0e10cSrcweir if( pGlyphAdvances )
554cdf0e10cSrcweir *(pGlyphAdvances++) = mpGlyphAdvances[ nStart ];
555cdf0e10cSrcweir if( pCharIndexes )
556cdf0e10cSrcweir {
557cdf0e10cSrcweir int nCharPos;
558cdf0e10cSrcweir if( !mpGlyphs2Chars )
559cdf0e10cSrcweir nCharPos = nStart + mnMinCharPos;
560cdf0e10cSrcweir else
561cdf0e10cSrcweir nCharPos = mpGlyphs2Chars[nStart];
562cdf0e10cSrcweir *(pCharIndexes++) = nCharPos;
563cdf0e10cSrcweir }
564cdf0e10cSrcweir
565cdf0e10cSrcweir // stop at last glyph
566cdf0e10cSrcweir if( ++nStart >= mnGlyphCount )
567cdf0e10cSrcweir break;
568cdf0e10cSrcweir
569cdf0e10cSrcweir // stop when next x-position is unexpected
570cdf0e10cSrcweir if( !pGlyphAdvances && mpGlyphOrigAdvs )
571cdf0e10cSrcweir if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
572cdf0e10cSrcweir break;
573cdf0e10cSrcweir }
574cdf0e10cSrcweir
575cdf0e10cSrcweir return nCount;
576cdf0e10cSrcweir }
577cdf0e10cSrcweir
578cdf0e10cSrcweir // -----------------------------------------------------------------------
579cdf0e10cSrcweir
580cdf0e10cSrcweir void Os2SalLayout::DrawText( SalGraphics& rGraphics ) const
581cdf0e10cSrcweir {
582cdf0e10cSrcweir if( mnGlyphCount <= 0 )
583cdf0e10cSrcweir return;
584cdf0e10cSrcweir
585cdf0e10cSrcweir Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
586cdf0e10cSrcweir POINTL aPt;
587cdf0e10cSrcweir APIRET rc;
588cdf0e10cSrcweir
589cdf0e10cSrcweir aPt.x = aPos.X();
590cdf0e10cSrcweir aPt.y = static_cast<Os2SalGraphics&>(rGraphics).mnHeight - aPos.Y();
591cdf0e10cSrcweir
592cdf0e10cSrcweir // ft2lib doesn't work with printer hps, so we fallback to codepage printing
593cdf0e10cSrcweir // until cp1200 support will work.
594cdf0e10cSrcweir if (static_cast<Os2SalGraphics&>(rGraphics).mbPrinter) {
595cdf0e10cSrcweir // convert to codepage
596cdf0e10cSrcweir ByteString str( mpOutGlyphs, gsl_getSystemTextEncoding() );
597cdf0e10cSrcweir // gliph size is not recalculated, so it could be wrong!
598cdf0e10cSrcweir rc = Ft2CharStringPosAtA( static_cast<Os2SalGraphics&>(rGraphics).mhPS,
599cdf0e10cSrcweir &aPt, NULL, CHS_VECTOR, mnGlyphCount, (PSZ)str.GetBuffer(),
600cdf0e10cSrcweir (LONG*)mpGlyphAdvances, 0);
601cdf0e10cSrcweir } else {
602cdf0e10cSrcweir // try unicode rendering to screen
603cdf0e10cSrcweir rc = Ft2CharStringPosAtW( static_cast<Os2SalGraphics&>(rGraphics).mhPS,
604cdf0e10cSrcweir &aPt, NULL, CHS_VECTOR, mnGlyphCount, (LPWSTR)mpOutGlyphs,
605cdf0e10cSrcweir (LONG*)mpGlyphAdvances, 0);
606cdf0e10cSrcweir if (rc == GPI_ERROR) {
607cdf0e10cSrcweir // if *W fails, convert to codepage and use *A (fallback to GPI into ft2)
608cdf0e10cSrcweir ByteString str( mpOutGlyphs, gsl_getSystemTextEncoding() );
609cdf0e10cSrcweir #if OSL_DEBUG_LEVEL>10
610cdf0e10cSrcweir debug_printf("Os2SalLayout::DrawText HPS %08x PosAtW failed '%s'!\n",static_cast<Os2SalGraphics&>(rGraphics).mhPS,str.GetBuffer());
611cdf0e10cSrcweir #endif
612cdf0e10cSrcweir // gliph size is not recalculated, so it could be wrong!
613cdf0e10cSrcweir rc = Ft2CharStringPosAtA( static_cast<Os2SalGraphics&>(rGraphics).mhPS,
614cdf0e10cSrcweir &aPt, NULL, CHS_VECTOR, mnGlyphCount, (PSZ)str.GetBuffer(),
615cdf0e10cSrcweir (LONG*)mpGlyphAdvances, 0);
616cdf0e10cSrcweir }
617cdf0e10cSrcweir }
618cdf0e10cSrcweir }
619cdf0e10cSrcweir
620cdf0e10cSrcweir // -----------------------------------------------------------------------
621cdf0e10cSrcweir
622cdf0e10cSrcweir long Os2SalLayout::FillDXArray( long* pDXArray ) const
623cdf0e10cSrcweir {
624cdf0e10cSrcweir if( !mnWidth )
625cdf0e10cSrcweir {
626cdf0e10cSrcweir long mnWidth = mnBaseAdv;
627cdf0e10cSrcweir for( int i = 0; i < mnGlyphCount; ++i )
628cdf0e10cSrcweir mnWidth += mpGlyphAdvances[ i ];
629cdf0e10cSrcweir }
630cdf0e10cSrcweir
631cdf0e10cSrcweir if( pDXArray != NULL )
632cdf0e10cSrcweir {
633cdf0e10cSrcweir for( int i = 0; i < mnCharCount; ++i )
634cdf0e10cSrcweir pDXArray[ i ] = mpCharWidths[ i ];
635cdf0e10cSrcweir }
636cdf0e10cSrcweir
637cdf0e10cSrcweir return mnWidth;
638cdf0e10cSrcweir }
639cdf0e10cSrcweir
640cdf0e10cSrcweir // -----------------------------------------------------------------------
641cdf0e10cSrcweir
642cdf0e10cSrcweir int Os2SalLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
643cdf0e10cSrcweir // NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
644cdf0e10cSrcweir {
645cdf0e10cSrcweir if( mnWidth )
646cdf0e10cSrcweir if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth )
647cdf0e10cSrcweir return STRING_LEN;
648cdf0e10cSrcweir
649cdf0e10cSrcweir long nExtraWidth = mnBaseAdv * nFactor;
650cdf0e10cSrcweir for( int n = 0; n < mnCharCount; ++n )
651cdf0e10cSrcweir {
652cdf0e10cSrcweir // skip unused characters
653cdf0e10cSrcweir if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) )
654cdf0e10cSrcweir continue;
655cdf0e10cSrcweir // add char widths until max
656cdf0e10cSrcweir nExtraWidth += mpCharWidths[ n ] * nFactor;
657cdf0e10cSrcweir if( nExtraWidth >= nMaxWidth )
658cdf0e10cSrcweir return (mnMinCharPos + n);
659cdf0e10cSrcweir nExtraWidth += nCharExtra;
660cdf0e10cSrcweir }
661cdf0e10cSrcweir
662cdf0e10cSrcweir return STRING_LEN;
663cdf0e10cSrcweir }
664cdf0e10cSrcweir
665cdf0e10cSrcweir // -----------------------------------------------------------------------
666cdf0e10cSrcweir
667cdf0e10cSrcweir void Os2SalLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
668cdf0e10cSrcweir {
669cdf0e10cSrcweir long nXPos = mnBaseAdv;
670cdf0e10cSrcweir
671cdf0e10cSrcweir if( !mpGlyphs2Chars )
672cdf0e10cSrcweir {
673cdf0e10cSrcweir for( int i = 0; i < nMaxIdx; i += 2 )
674cdf0e10cSrcweir {
675cdf0e10cSrcweir pCaretXArray[ i ] = nXPos;
676cdf0e10cSrcweir nXPos += mpGlyphAdvances[ i>>1 ];
677cdf0e10cSrcweir pCaretXArray[ i+1 ] = nXPos;
678cdf0e10cSrcweir }
679cdf0e10cSrcweir }
680cdf0e10cSrcweir else
681cdf0e10cSrcweir {
682cdf0e10cSrcweir int i;
683cdf0e10cSrcweir for( i = 0; i < nMaxIdx; ++i )
684cdf0e10cSrcweir pCaretXArray[ i ] = -1;
685cdf0e10cSrcweir
686cdf0e10cSrcweir // assign glyph positions to character positions
687cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
688cdf0e10cSrcweir {
689cdf0e10cSrcweir int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos;
690cdf0e10cSrcweir long nXRight = nXPos + mpCharWidths[ nCurrIdx ];
691cdf0e10cSrcweir nCurrIdx *= 2;
692cdf0e10cSrcweir if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) )
693cdf0e10cSrcweir {
694cdf0e10cSrcweir // normal positions for LTR case
695cdf0e10cSrcweir pCaretXArray[ nCurrIdx ] = nXPos;
696cdf0e10cSrcweir pCaretXArray[ nCurrIdx+1 ] = nXRight;
697cdf0e10cSrcweir }
698cdf0e10cSrcweir else
699cdf0e10cSrcweir {
700cdf0e10cSrcweir // reverse positions for RTL case
701cdf0e10cSrcweir pCaretXArray[ nCurrIdx ] = nXRight;
702cdf0e10cSrcweir pCaretXArray[ nCurrIdx+1 ] = nXPos;
703cdf0e10cSrcweir }
704cdf0e10cSrcweir nXPos += mpGlyphAdvances[ i ];
705cdf0e10cSrcweir }
706cdf0e10cSrcweir }
707cdf0e10cSrcweir }
708cdf0e10cSrcweir
709cdf0e10cSrcweir // -----------------------------------------------------------------------
710cdf0e10cSrcweir
711cdf0e10cSrcweir void Os2SalLayout::Justify( long nNewWidth )
712cdf0e10cSrcweir {
713cdf0e10cSrcweir long nOldWidth = mnWidth;
714cdf0e10cSrcweir mnWidth = nNewWidth;
715cdf0e10cSrcweir
716cdf0e10cSrcweir if( mnGlyphCount <= 0 )
717cdf0e10cSrcweir return;
718cdf0e10cSrcweir
719cdf0e10cSrcweir if( nNewWidth == nOldWidth )
720cdf0e10cSrcweir return;
721cdf0e10cSrcweir
722cdf0e10cSrcweir // the rightmost glyph cannot be stretched
723cdf0e10cSrcweir const int nRight = mnGlyphCount - 1;
724cdf0e10cSrcweir nOldWidth -= mpGlyphAdvances[ nRight ];
725cdf0e10cSrcweir nNewWidth -= mpGlyphAdvances[ nRight ];
726cdf0e10cSrcweir
727cdf0e10cSrcweir // count stretchable glyphs
728cdf0e10cSrcweir int nStretchable = 0, i;
729cdf0e10cSrcweir for( i = 0; i < nRight; ++i )
730cdf0e10cSrcweir if( mpGlyphAdvances[i] >= 0 )
731cdf0e10cSrcweir ++nStretchable;
732cdf0e10cSrcweir
733cdf0e10cSrcweir // stretch these glyphs
734cdf0e10cSrcweir int nDiffWidth = nNewWidth - nOldWidth;
735cdf0e10cSrcweir for( i = 0; (i < nRight) && (nStretchable > 0); ++i )
736cdf0e10cSrcweir {
737cdf0e10cSrcweir if( mpGlyphAdvances[i] <= 0 )
738cdf0e10cSrcweir continue;
739cdf0e10cSrcweir int nDeltaWidth = nDiffWidth / nStretchable;
740cdf0e10cSrcweir mpGlyphAdvances[i] += nDeltaWidth;
741cdf0e10cSrcweir --nStretchable;
742cdf0e10cSrcweir nDiffWidth -= nDeltaWidth;
743cdf0e10cSrcweir }
744cdf0e10cSrcweir }
745cdf0e10cSrcweir
746cdf0e10cSrcweir // -----------------------------------------------------------------------
747cdf0e10cSrcweir
748cdf0e10cSrcweir void Os2SalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
749cdf0e10cSrcweir {
750cdf0e10cSrcweir SalLayout::AdjustLayout( rArgs );
751cdf0e10cSrcweir
752cdf0e10cSrcweir // adjust positions if requested
753cdf0e10cSrcweir if( rArgs.mpDXArray )
754cdf0e10cSrcweir ApplyDXArray( rArgs );
755cdf0e10cSrcweir else if( rArgs.mnLayoutWidth )
756cdf0e10cSrcweir Justify( rArgs.mnLayoutWidth );
757cdf0e10cSrcweir else
758cdf0e10cSrcweir return;
759cdf0e10cSrcweir
760cdf0e10cSrcweir // recalculate virtual char widths if they were changed
761cdf0e10cSrcweir if( mpCharWidths != mpGlyphAdvances )
762cdf0e10cSrcweir {
763cdf0e10cSrcweir int i;
764cdf0e10cSrcweir if( !mpGlyphs2Chars )
765cdf0e10cSrcweir {
766cdf0e10cSrcweir // standard LTR case
767cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
768cdf0e10cSrcweir mpCharWidths[ i ] = mpGlyphAdvances[ i ];
769cdf0e10cSrcweir }
770cdf0e10cSrcweir else
771cdf0e10cSrcweir {
772cdf0e10cSrcweir // BiDi or complex case
773cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i )
774cdf0e10cSrcweir mpCharWidths[ i ] = 0;
775cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
776cdf0e10cSrcweir {
777cdf0e10cSrcweir int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
778cdf0e10cSrcweir if( j >= 0 )
779cdf0e10cSrcweir mpCharWidths[ j ] += mpGlyphAdvances[ i ];
780cdf0e10cSrcweir }
781cdf0e10cSrcweir }
782cdf0e10cSrcweir }
783cdf0e10cSrcweir }
784cdf0e10cSrcweir
785cdf0e10cSrcweir // -----------------------------------------------------------------------
786cdf0e10cSrcweir
787cdf0e10cSrcweir void Os2SalLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
788cdf0e10cSrcweir {
789cdf0e10cSrcweir // try to avoid disturbance of text flow for LSB rounding case;
790cdf0e10cSrcweir const long* pDXArray = rArgs.mpDXArray;
791cdf0e10cSrcweir
792cdf0e10cSrcweir int i = 0;
793cdf0e10cSrcweir long nOldWidth = mnBaseAdv;
794cdf0e10cSrcweir for(; i < mnCharCount; ++i )
795cdf0e10cSrcweir {
796cdf0e10cSrcweir int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
797cdf0e10cSrcweir if( j >= 0 )
798cdf0e10cSrcweir {
799cdf0e10cSrcweir nOldWidth += mpGlyphAdvances[ j ];
800cdf0e10cSrcweir int nDiff = nOldWidth - pDXArray[ i ];
801cdf0e10cSrcweir
802cdf0e10cSrcweir // disabled because of #104768#
803cdf0e10cSrcweir // works great for static text, but problems when typing
804cdf0e10cSrcweir // if( nDiff>+1 || nDiff<-1 )
805cdf0e10cSrcweir // only bother with changing anything when something moved
806cdf0e10cSrcweir if( nDiff != 0 )
807cdf0e10cSrcweir break;
808cdf0e10cSrcweir }
809cdf0e10cSrcweir }
810cdf0e10cSrcweir if( i >= mnCharCount )
811cdf0e10cSrcweir return;
812cdf0e10cSrcweir
813cdf0e10cSrcweir if( !mpGlyphOrigAdvs )
814cdf0e10cSrcweir {
815cdf0e10cSrcweir mpGlyphOrigAdvs = new int[ mnGlyphCount ];
816cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
817cdf0e10cSrcweir mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ];
818cdf0e10cSrcweir }
819cdf0e10cSrcweir
820cdf0e10cSrcweir mnWidth = mnBaseAdv;
821cdf0e10cSrcweir for( i = 0; i < mnCharCount; ++i )
822cdf0e10cSrcweir {
823cdf0e10cSrcweir int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
824cdf0e10cSrcweir if( j >= 0 )
825cdf0e10cSrcweir mpGlyphAdvances[j] = pDXArray[i] - mnWidth;
826cdf0e10cSrcweir mnWidth = pDXArray[i];
827cdf0e10cSrcweir }
828cdf0e10cSrcweir }
829cdf0e10cSrcweir
830cdf0e10cSrcweir // -----------------------------------------------------------------------
831cdf0e10cSrcweir
832cdf0e10cSrcweir void Os2SalLayout::MoveGlyph( int nStart, long nNewXPos )
833cdf0e10cSrcweir {
834cdf0e10cSrcweir if( nStart > mnGlyphCount )
835cdf0e10cSrcweir return;
836cdf0e10cSrcweir
837cdf0e10cSrcweir // calculate the current x-position of the requested glyph
838cdf0e10cSrcweir // TODO: cache absolute positions
839cdf0e10cSrcweir int nXPos = mnBaseAdv;
840cdf0e10cSrcweir for( int i = 0; i < nStart; ++i )
841cdf0e10cSrcweir nXPos += mpGlyphAdvances[i];
842cdf0e10cSrcweir
843cdf0e10cSrcweir // calculate the difference to the current glyph position
844cdf0e10cSrcweir int nDelta = nNewXPos - nXPos;
845cdf0e10cSrcweir
846cdf0e10cSrcweir // adjust the width of the layout if it was already cached
847cdf0e10cSrcweir if( mnWidth )
848cdf0e10cSrcweir mnWidth += nDelta;
849cdf0e10cSrcweir
850cdf0e10cSrcweir // depending on whether the requested glyph is leftmost in the layout
851cdf0e10cSrcweir // adjust either the layout's or the requested glyph's relative position
852cdf0e10cSrcweir if( nStart > 0 )
853cdf0e10cSrcweir mpGlyphAdvances[ nStart-1 ] += nDelta;
854cdf0e10cSrcweir else
855cdf0e10cSrcweir mnBaseAdv += nDelta;
856cdf0e10cSrcweir }
857cdf0e10cSrcweir
858cdf0e10cSrcweir // -----------------------------------------------------------------------
859cdf0e10cSrcweir
860cdf0e10cSrcweir void Os2SalLayout::DropGlyph( int nStart )
861cdf0e10cSrcweir {
862cdf0e10cSrcweir mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
863cdf0e10cSrcweir }
864cdf0e10cSrcweir
865cdf0e10cSrcweir // -----------------------------------------------------------------------
866cdf0e10cSrcweir
867cdf0e10cSrcweir void Os2SalLayout::Simplify( bool bIsBase )
868cdf0e10cSrcweir {
869cdf0e10cSrcweir // return early if no glyph has been dropped
870cdf0e10cSrcweir int i = mnGlyphCount;
871cdf0e10cSrcweir while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) );
872cdf0e10cSrcweir if( i < 0 )
873cdf0e10cSrcweir return;
874cdf0e10cSrcweir
875cdf0e10cSrcweir // convert the layout to a sparse layout if it is not already
876cdf0e10cSrcweir if( !mpGlyphs2Chars )
877cdf0e10cSrcweir {
878cdf0e10cSrcweir mpGlyphs2Chars = new int[ mnGlyphCount ];
879cdf0e10cSrcweir mpCharWidths = new int[ mnCharCount ];
880cdf0e10cSrcweir // assertion: mnGlyphCount == mnCharCount
881cdf0e10cSrcweir for( int k = 0; k < mnGlyphCount; ++k )
882cdf0e10cSrcweir {
883cdf0e10cSrcweir mpGlyphs2Chars[ k ] = mnMinCharPos + k;
884cdf0e10cSrcweir mpCharWidths[ k ] = mpGlyphAdvances[ k ];
885cdf0e10cSrcweir }
886cdf0e10cSrcweir }
887cdf0e10cSrcweir
888cdf0e10cSrcweir // remove dropped glyphs that are rightmost in the layout
889cdf0e10cSrcweir for( i = mnGlyphCount; --i >= 0; )
890cdf0e10cSrcweir {
891cdf0e10cSrcweir if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH )
892cdf0e10cSrcweir break;
893cdf0e10cSrcweir if( mnWidth )
894cdf0e10cSrcweir mnWidth -= mpGlyphAdvances[ i ];
895cdf0e10cSrcweir int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
896cdf0e10cSrcweir if( nRelCharPos >= 0 )
897cdf0e10cSrcweir mpCharWidths[ nRelCharPos ] = 0;
898cdf0e10cSrcweir }
899cdf0e10cSrcweir mnGlyphCount = i + 1;
900cdf0e10cSrcweir
901cdf0e10cSrcweir // keep original glyph widths around
902cdf0e10cSrcweir if( !mpGlyphOrigAdvs )
903cdf0e10cSrcweir {
904cdf0e10cSrcweir mpGlyphOrigAdvs = new int[ mnGlyphCount ];
905cdf0e10cSrcweir for( int k = 0; k < mnGlyphCount; ++k )
906cdf0e10cSrcweir mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ];
907cdf0e10cSrcweir }
908cdf0e10cSrcweir
909cdf0e10cSrcweir // remove dropped glyphs inside the layout
910cdf0e10cSrcweir int nNewGC = 0;
911cdf0e10cSrcweir for( i = 0; i < mnGlyphCount; ++i )
912cdf0e10cSrcweir {
913cdf0e10cSrcweir if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
914cdf0e10cSrcweir {
915cdf0e10cSrcweir // adjust relative position to last valid glyph
916cdf0e10cSrcweir int nDroppedWidth = mpGlyphAdvances[ i ];
917cdf0e10cSrcweir mpGlyphAdvances[ i ] = 0;
918cdf0e10cSrcweir if( nNewGC > 0 )
919cdf0e10cSrcweir mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth;
920cdf0e10cSrcweir else
921cdf0e10cSrcweir mnBaseAdv += nDroppedWidth;
922cdf0e10cSrcweir
923cdf0e10cSrcweir // zero the virtual char width for the char that has a fallback
924cdf0e10cSrcweir int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
925cdf0e10cSrcweir if( nRelCharPos >= 0 )
926cdf0e10cSrcweir mpCharWidths[ nRelCharPos ] = 0;
927cdf0e10cSrcweir }
928cdf0e10cSrcweir else
929cdf0e10cSrcweir {
930cdf0e10cSrcweir if( nNewGC != i )
931cdf0e10cSrcweir {
932cdf0e10cSrcweir // rearrange the glyph array to get rid of the dropped glyph
933cdf0e10cSrcweir mpOutGlyphs[ nNewGC ] = mpOutGlyphs[ i ];
934cdf0e10cSrcweir mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ];
935cdf0e10cSrcweir mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ];
936cdf0e10cSrcweir mpGlyphs2Chars[ nNewGC ] = mpGlyphs2Chars[ i ];
937cdf0e10cSrcweir }
938cdf0e10cSrcweir ++nNewGC;
939cdf0e10cSrcweir }
940cdf0e10cSrcweir }
941cdf0e10cSrcweir
942cdf0e10cSrcweir mnGlyphCount = nNewGC;
943cdf0e10cSrcweir if( mnGlyphCount <= 0 )
944cdf0e10cSrcweir mnWidth = mnBaseAdv = 0;
945cdf0e10cSrcweir }
946cdf0e10cSrcweir
947cdf0e10cSrcweir // =======================================================================
948cdf0e10cSrcweir
949cdf0e10cSrcweir SalLayout* Os2SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
950cdf0e10cSrcweir {
951cdf0e10cSrcweir Os2SalLayout* pLayout = NULL;
952cdf0e10cSrcweir DBG_ASSERT( mpOs2FontEntry[nFallbackLevel], "WinSalGraphics mpWinFontEntry==NULL");
953cdf0e10cSrcweir
954cdf0e10cSrcweir const ImplOs2FontData& rFontFace = *mpOs2FontData[ nFallbackLevel ];
955cdf0e10cSrcweir ImplOs2FontEntry& rFontInstance = *mpOs2FontEntry[ nFallbackLevel ];
956cdf0e10cSrcweir
957cdf0e10cSrcweir {
958cdf0e10cSrcweir #ifdef GCP_KERN_HACK
959cdf0e10cSrcweir if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) && !rFontInstance.HasKernData() )
960cdf0e10cSrcweir {
961cdf0e10cSrcweir // TODO: directly cache kerning info in the rFontInstance
962cdf0e10cSrcweir // TODO: get rid of kerning methods+data in WinSalGraphics object
963cdf0e10cSrcweir GetKernPairs( 0, NULL );
964cdf0e10cSrcweir rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
965cdf0e10cSrcweir }
966cdf0e10cSrcweir #endif // GCP_KERN_HACK
967cdf0e10cSrcweir
968fc9fd3f1SPedro Giffuni //PM_BYTE eCharSet = ANSI_CHARSET;
969cdf0e10cSrcweir //if( mpLogFont )
970cdf0e10cSrcweir // eCharSet = mpLogFont->lfCharSet;
971cdf0e10cSrcweir pLayout = new Os2SalLayout( mhPS, 0, rFontFace, rFontInstance );
972cdf0e10cSrcweir }
973cdf0e10cSrcweir
974cdf0e10cSrcweir if( mfFontScale != 1.0 )
975cdf0e10cSrcweir pLayout->SetFontScale( mfFontScale );
976cdf0e10cSrcweir
977cdf0e10cSrcweir return pLayout;
978cdf0e10cSrcweir }
979cdf0e10cSrcweir
980cdf0e10cSrcweir // =======================================================================
981cdf0e10cSrcweir
982cdf0e10cSrcweir ImplOs2FontEntry::ImplOs2FontEntry( ImplFontSelectData& rFSD )
983cdf0e10cSrcweir : ImplFontEntry( rFSD ),
984cdf0e10cSrcweir maWidthMap( 512 )
985cdf0e10cSrcweir #ifdef GCP_KERN_HACK
986cdf0e10cSrcweir ,mpKerningPairs( NULL )
987cdf0e10cSrcweir ,mnKerningPairs( -1 )
988cdf0e10cSrcweir #endif // GCP_KERN_HACK
989cdf0e10cSrcweir {
990cdf0e10cSrcweir }
991cdf0e10cSrcweir
992cdf0e10cSrcweir // -----------------------------------------------------------------------
993cdf0e10cSrcweir
994cdf0e10cSrcweir ImplOs2FontEntry::~ImplOs2FontEntry()
995cdf0e10cSrcweir {
996cdf0e10cSrcweir #ifdef GCP_KERN_HACK
997cdf0e10cSrcweir delete[] mpKerningPairs;
998cdf0e10cSrcweir #endif // GCP_KERN_HACK
999cdf0e10cSrcweir }
1000cdf0e10cSrcweir
1001cdf0e10cSrcweir // -----------------------------------------------------------------------
1002cdf0e10cSrcweir
1003cdf0e10cSrcweir #ifdef GCP_KERN_HACK
1004cdf0e10cSrcweir bool ImplOs2FontEntry::HasKernData() const
1005cdf0e10cSrcweir {
1006cdf0e10cSrcweir return (mnKerningPairs >= 0);
1007cdf0e10cSrcweir }
1008cdf0e10cSrcweir
1009cdf0e10cSrcweir // -----------------------------------------------------------------------
1010cdf0e10cSrcweir
1011cdf0e10cSrcweir void ImplOs2FontEntry::SetKernData( int nPairCount, const KERNINGPAIRS* pPairData )
1012cdf0e10cSrcweir {
1013cdf0e10cSrcweir mnKerningPairs = nPairCount;
1014cdf0e10cSrcweir mpKerningPairs = new KERNINGPAIRS[ mnKerningPairs ];
1015cdf0e10cSrcweir ::memcpy( mpKerningPairs, (const void*)pPairData, nPairCount*sizeof(KERNINGPAIRS) );
1016cdf0e10cSrcweir }
1017cdf0e10cSrcweir
1018cdf0e10cSrcweir // -----------------------------------------------------------------------
1019cdf0e10cSrcweir
1020cdf0e10cSrcweir int ImplOs2FontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const
1021cdf0e10cSrcweir {
1022cdf0e10cSrcweir int nKernAmount = 0;
1023cdf0e10cSrcweir if( mpKerningPairs )
1024cdf0e10cSrcweir {
1025cdf0e10cSrcweir const KERNINGPAIRS aRefPair = { cLeft, cRight, 0 };
1026cdf0e10cSrcweir const KERNINGPAIRS* pFirstPair = mpKerningPairs;
1027cdf0e10cSrcweir const KERNINGPAIRS* pEndPair = mpKerningPairs + mnKerningPairs;
1028cdf0e10cSrcweir const KERNINGPAIRS* pPair = std::lower_bound( pFirstPair,
1029cdf0e10cSrcweir pEndPair, aRefPair, ImplCmpKernData );
1030cdf0e10cSrcweir if( (pPair != pEndPair)
1031cdf0e10cSrcweir && (pPair->sFirstChar == aRefPair.sFirstChar)
1032cdf0e10cSrcweir && (pPair->sSecondChar == aRefPair.sSecondChar) )
1033cdf0e10cSrcweir nKernAmount = pPair->lKerningAmount;
1034cdf0e10cSrcweir }
1035cdf0e10cSrcweir
1036cdf0e10cSrcweir return nKernAmount;
1037cdf0e10cSrcweir }
1038cdf0e10cSrcweir #endif // GCP_KERN_HACK
1039cdf0e10cSrcweir
1040cdf0e10cSrcweir // =======================================================================
1041cdf0e10cSrcweir
1042cdf0e10cSrcweir ImplFontData* ImplOs2FontData::Clone() const
1043cdf0e10cSrcweir {
1044cdf0e10cSrcweir if( mpUnicodeMap )
1045cdf0e10cSrcweir mpUnicodeMap->AddReference();
1046cdf0e10cSrcweir ImplFontData* pClone = new ImplOs2FontData( *this );
1047cdf0e10cSrcweir return pClone;
1048cdf0e10cSrcweir }
1049cdf0e10cSrcweir
1050cdf0e10cSrcweir // -----------------------------------------------------------------------
1051cdf0e10cSrcweir
1052cdf0e10cSrcweir ImplFontEntry* ImplOs2FontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
1053cdf0e10cSrcweir {
1054cdf0e10cSrcweir //debug_printf("ImplOs2FontData::CreateFontInstance\n");
1055cdf0e10cSrcweir ImplFontEntry* pEntry = new ImplOs2FontEntry( rFSD );
1056cdf0e10cSrcweir return pEntry;
1057cdf0e10cSrcweir }
1058cdf0e10cSrcweir
1059cdf0e10cSrcweir // =======================================================================
1060cdf0e10cSrcweir
1061