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