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 93 inline void ImplOs2FontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth ) 94 { 95 maWidthMap[ nCharCode ] = nCharWidth; 96 } 97 98 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; 113 void SetFontScale( float f ) { mfFontScale = f; } 114 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 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 189 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 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 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 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* pGlyphs, 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 {nGlyphIndex,nCharPos,nGlyphAdvance} 531 long nGlyphIndex = mpOutGlyphs[ nStart ]; 532 if( mbDisableGlyphs ) 533 { 534 if( mnLayoutFlags & SAL_LAYOUT_VERTICAL ) 535 { 536 sal_Unicode cChar = (sal_Unicode)(nGlyphIndex & GF_IDXMASK); 537 #ifdef GNG_VERT_HACK 538 if( mrOs2FontData.HasGSUBstitutions( mhPS ) 539 && mrOs2FontData.IsGSUBstituted( cChar ) ) 540 nGlyphIndex |= GF_ROTL | GF_GSUB; 541 else 542 #endif // GNG_VERT_HACK 543 { 544 nGlyphIndex |= GetVerticalFlags( cChar ); 545 if( !(nGlyphIndex & GF_ROTMASK) ) 546 nGlyphIndex |= GF_VERT; 547 } 548 } 549 nGlyphIndex |= GF_ISCHAR; 550 } 551 ++nCount; 552 *(pGlyphs++) = nGlyphIndex; 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