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