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