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