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