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