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