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 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 #define ENABLE_ICU_LAYOUT 28 #include <gcach_ftyp.hxx> 29 #include <sallayout.hxx> 30 #include <salgdi.hxx> 31 32 #include <vcl/svapp.hxx> 33 34 #include <sal/alloca.h> 35 36 #if OSL_DEBUG_LEVEL > 1 37 #include <cstdio> 38 #endif 39 #include <rtl/instance.hxx> 40 41 namespace { struct SimpleLayoutEngine : public rtl::Static< ServerFontLayoutEngine, SimpleLayoutEngine > {}; } 42 43 // ======================================================================= 44 // layout implementation for ServerFont 45 // ======================================================================= 46 47 ServerFontLayout::ServerFontLayout( ServerFont& rFont ) 48 : mrServerFont( rFont ) 49 {} 50 51 void ServerFontLayout::DrawText( SalGraphics& rSalGraphics ) const 52 { 53 rSalGraphics.DrawServerFontLayout( *this ); 54 } 55 56 // ----------------------------------------------------------------------- 57 58 bool ServerFontLayout::LayoutText( ImplLayoutArgs& rArgs ) 59 { 60 ServerFontLayoutEngine* pLE = NULL; 61 if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED) ) 62 pLE = mrServerFont.GetLayoutEngine(); 63 if( !pLE ) 64 pLE = &SimpleLayoutEngine::get(); 65 66 bool bRet = (*pLE)( *this, rArgs ); 67 return bRet; 68 } 69 70 // ----------------------------------------------------------------------- 71 72 void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs ) 73 { 74 GenericSalLayout::AdjustLayout( rArgs ); 75 76 // apply asian kerning if the glyphs are not already formatted 77 if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN) 78 && !(rArgs.mnFlags & SAL_LAYOUT_VERTICAL) ) 79 if( (rArgs.mpDXArray != NULL) || (rArgs.mnLayoutWidth != 0) ) 80 ApplyAsianKerning( rArgs.mpStr, rArgs.mnLength ); 81 82 // insert kashidas where requested by the formatting array 83 if( (rArgs.mnFlags & SAL_LAYOUT_KASHIDA_JUSTIFICATON) && rArgs.mpDXArray ) 84 { 85 int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 ); 86 if( nKashidaIndex != 0 ) 87 { 88 const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex ); 89 KashidaJustify( nKashidaIndex, rGM.GetCharWidth() ); 90 // TODO: kashida-GSUB/GPOS 91 } 92 } 93 } 94 95 // ======================================================================= 96 97 bool ServerFontLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs ) 98 { 99 FreetypeServerFont& rFont = static_cast<FreetypeServerFont&>(rLayout.GetServerFont()); 100 101 Point aNewPos( 0, 0 ); 102 sal_GlyphId nOldGlyphId( GF_DROPPED); 103 int nGlyphWidth = 0; 104 GlyphItem aPrevItem; 105 bool bRightToLeft; 106 for( int nCharPos = -1; rArgs.GetNextPos( &nCharPos, &bRightToLeft ); ) 107 { 108 sal_UCS4 cChar = rArgs.mpStr[ nCharPos ]; 109 if( (cChar >= 0xD800) && (cChar <= 0xDFFF) ) 110 { 111 if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed 112 continue; 113 cChar = 0x10000 + ((cChar - 0xD800) << 10) 114 + (rArgs.mpStr[ nCharPos+1 ] - 0xDC00); 115 } 116 117 if( bRightToLeft ) 118 cChar = GetMirroredChar( cChar ); 119 sal_GlyphId aGlyphId = rFont.GetGlyphIndex( cChar ); 120 // when glyph fallback is needed update LayoutArgs 121 if( !aGlyphId ) { 122 rArgs.NeedFallback( nCharPos, bRightToLeft ); 123 if( cChar >= 0x10000 ) // handle surrogate pairs 124 rArgs.NeedFallback( nCharPos+1, bRightToLeft ); 125 } 126 127 // apply pair kerning to prev glyph if requested 128 if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags ) 129 { 130 int nKernValue = rFont.GetGlyphKernValue( nOldGlyphId, aGlyphId ); 131 nGlyphWidth += nKernValue; 132 aPrevItem.mnNewWidth = nGlyphWidth; 133 } 134 135 // finish previous glyph 136 if( nOldGlyphId != GF_DROPPED ) 137 rLayout.AppendGlyph( aPrevItem ); 138 aNewPos.X() += nGlyphWidth; 139 140 // prepare GlyphItem for appending it in next round 141 nOldGlyphId = aGlyphId; 142 const GlyphMetric& rGM = rFont.GetGlyphMetric( aGlyphId ); 143 nGlyphWidth = rGM.GetCharWidth(); 144 int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0; 145 aPrevItem = GlyphItem( nCharPos, aGlyphId, aNewPos, nGlyphFlags, nGlyphWidth ); 146 } 147 148 // append last glyph item if any 149 if( nOldGlyphId != GF_DROPPED ) 150 rLayout.AppendGlyph( aPrevItem ); 151 152 return true; 153 } 154 155 // ======================================================================= 156 // bridge to ICU LayoutEngine 157 // ======================================================================= 158 159 #ifdef ENABLE_ICU_LAYOUT 160 161 #define bool_t signed char 162 163 // disable warnings in icu layout headers 164 #if defined __SUNPRO_CC 165 #pragma disable_warn 166 #endif 167 168 #include <layout/LayoutEngine.h> 169 #include <layout/LEFontInstance.h> 170 #include <layout/LEScripts.h> 171 172 // enable warnings again 173 #if defined __SUNPRO_CC 174 #pragma enable_warn 175 #endif 176 177 #include <unicode/uscript.h> 178 #include <unicode/ubidi.h> 179 180 using namespace U_ICU_NAMESPACE; 181 182 static const LEGlyphID ICU_DELETED_GLYPH = 0xFFFF; 183 static const LEGlyphID ICU_MARKED_GLYPH = 0xFFFE; 184 185 // ----------------------------------------------------------------------- 186 187 class IcuFontFromServerFont 188 : public LEFontInstance 189 { 190 private: 191 FreetypeServerFont& mrServerFont; 192 193 public: 194 IcuFontFromServerFont( FreetypeServerFont& rFont ) 195 : mrServerFont( rFont ) 196 {} 197 198 virtual const void* getFontTable(LETag tableTag) const; 199 virtual le_int32 getUnitsPerEM() const; 200 virtual float getXPixelsPerEm() const; 201 virtual float getYPixelsPerEm() const; 202 virtual float getScaleFactorX() const; 203 virtual float getScaleFactorY() const; 204 205 using LEFontInstance::mapCharToGlyph; 206 virtual LEGlyphID mapCharToGlyph( LEUnicode32 ch ) const; 207 208 virtual le_int32 getAscent() const; 209 virtual le_int32 getDescent() const; 210 virtual le_int32 getLeading() const; 211 212 virtual void getGlyphAdvance( LEGlyphID glyph, LEPoint &advance ) const; 213 virtual le_bool getGlyphPoint( LEGlyphID glyph, le_int32 pointNumber, LEPoint& point ) const; 214 }; 215 216 // ----------------------------------------------------------------------- 217 218 const void* IcuFontFromServerFont::getFontTable( LETag nICUTableTag ) const 219 { 220 char pTagName[5]; 221 pTagName[0] = (char)(nICUTableTag >> 24); 222 pTagName[1] = (char)(nICUTableTag >> 16); 223 pTagName[2] = (char)(nICUTableTag >> 8); 224 pTagName[3] = (char)(nICUTableTag); 225 pTagName[4] = 0; 226 227 sal_uLong nLength; 228 const unsigned char* pBuffer = mrServerFont.GetTable( pTagName, &nLength ); 229 #ifdef VERBOSE_DEBUG 230 fprintf(stderr,"IcuGetTable(\"%s\") => %p\n", pTagName, pBuffer); 231 int mnHeight = mrServerFont.GetFontSelData().mnHeight; 232 const char* pName = mrServerFont.GetFontFileName()->getStr(); 233 fprintf(stderr,"font( h=%d, \"%s\" )\n", mnHeight, pName ); 234 #endif 235 return (const void*)pBuffer; 236 } 237 238 // ----------------------------------------------------------------------- 239 240 le_int32 IcuFontFromServerFont::getUnitsPerEM() const 241 { 242 return mrServerFont.GetEmUnits(); 243 } 244 245 // ----------------------------------------------------------------------- 246 247 float IcuFontFromServerFont::getXPixelsPerEm() const 248 { 249 const ImplFontSelectData& r = mrServerFont.GetFontSelData(); 250 float fX = r.mnWidth ? r.mnWidth : r.mnHeight; 251 return fX; 252 } 253 254 // ----------------------------------------------------------------------- 255 256 float IcuFontFromServerFont::getYPixelsPerEm() const 257 { 258 float fY = mrServerFont.GetFontSelData().mnHeight; 259 return fY; 260 } 261 262 // ----------------------------------------------------------------------- 263 264 float IcuFontFromServerFont::getScaleFactorX() const 265 { 266 return 1.0; 267 } 268 269 // ----------------------------------------------------------------------- 270 271 float IcuFontFromServerFont::getScaleFactorY() const 272 { 273 return 1.0; 274 } 275 276 // ----------------------------------------------------------------------- 277 278 LEGlyphID IcuFontFromServerFont::mapCharToGlyph( LEUnicode32 ch ) const 279 { 280 LEGlyphID nGlyphIndex = mrServerFont.GetRawGlyphIndex( ch ); 281 return nGlyphIndex; 282 } 283 284 // ----------------------------------------------------------------------- 285 286 le_int32 IcuFontFromServerFont::getAscent() const 287 { 288 const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT(); 289 le_int32 nAscent = (+rMetrics.ascender + 32) >> 6; 290 return nAscent; 291 } 292 293 // ----------------------------------------------------------------------- 294 295 le_int32 IcuFontFromServerFont::getDescent() const 296 { 297 const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT(); 298 le_int32 nDescent = (-rMetrics.descender + 32) >> 6; 299 return nDescent; 300 } 301 302 // ----------------------------------------------------------------------- 303 304 le_int32 IcuFontFromServerFont::getLeading() const 305 { 306 const FT_Size_Metrics& rMetrics = mrServerFont.GetMetricsFT(); 307 le_int32 nLeading = ((rMetrics.height - rMetrics.ascender + rMetrics.descender) + 32) >> 6; 308 return nLeading; 309 } 310 311 // ----------------------------------------------------------------------- 312 313 void IcuFontFromServerFont::getGlyphAdvance( LEGlyphID nGlyphIndex, 314 LEPoint &advance ) const 315 { 316 if( (nGlyphIndex == ICU_MARKED_GLYPH) 317 || (nGlyphIndex == ICU_DELETED_GLYPH) ) 318 { 319 // deleted glyph or mark glyph has not advance 320 advance.fX = 0; 321 } 322 else 323 { 324 const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nGlyphIndex ); 325 advance.fX = rGM.GetCharWidth(); 326 } 327 328 advance.fY = 0; 329 } 330 331 // ----------------------------------------------------------------------- 332 333 le_bool IcuFontFromServerFont::getGlyphPoint( LEGlyphID, 334 le_int32 335 #if OSL_DEBUG_LEVEL > 1 336 pointNumber 337 #endif 338 , 339 LEPoint& ) const 340 { 341 //TODO: replace dummy implementation 342 #if OSL_DEBUG_LEVEL > 1 343 fprintf(stderr,"getGlyphPoint(%d)\n", pointNumber ); 344 #endif 345 return false; 346 } 347 348 // ======================================================================= 349 350 class IcuLayoutEngine : public ServerFontLayoutEngine 351 { 352 private: 353 IcuFontFromServerFont maIcuFont; 354 355 le_int32 meScriptCode; 356 LayoutEngine* mpIcuLE; 357 358 public: 359 IcuLayoutEngine( FreetypeServerFont& ); 360 virtual ~IcuLayoutEngine(); 361 362 virtual bool operator()( ServerFontLayout&, ImplLayoutArgs& ); 363 }; 364 365 // ----------------------------------------------------------------------- 366 367 IcuLayoutEngine::IcuLayoutEngine( FreetypeServerFont& rServerFont ) 368 : maIcuFont( rServerFont ), 369 meScriptCode( USCRIPT_INVALID_CODE ), 370 mpIcuLE( NULL ) 371 {} 372 373 // ----------------------------------------------------------------------- 374 375 IcuLayoutEngine::~IcuLayoutEngine() 376 { 377 if( mpIcuLE ) 378 delete mpIcuLE; 379 } 380 381 // ----------------------------------------------------------------------- 382 383 static bool lcl_CharIsJoiner(sal_Unicode cChar) 384 { 385 return ((cChar == 0x200C) || (cChar == 0x200D)); 386 } 387 388 bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs ) 389 { 390 LEUnicode* pIcuChars; 391 if( sizeof(LEUnicode) == sizeof(*rArgs.mpStr) ) 392 pIcuChars = (LEUnicode*)rArgs.mpStr; 393 else 394 { 395 // this conversion will only be needed when either 396 // ICU's or OOo's unicodes stop being unsigned shorts 397 // TODO: watch out for surrogates! 398 pIcuChars = (LEUnicode*)alloca( rArgs.mnLength * sizeof(LEUnicode) ); 399 for( xub_StrLen ic = 0; ic < rArgs.mnLength; ++ic ) 400 pIcuChars[ic] = static_cast<LEUnicode>( rArgs.mpStr[ic] ); 401 } 402 403 // allocate temporary arrays, note: round to even 404 int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos ) | 15) + 1; 405 406 struct IcuPosition{ float fX, fY; }; 407 const int nAllocSize = sizeof(LEGlyphID) + sizeof(le_int32) + sizeof(IcuPosition); 408 LEGlyphID* pIcuGlyphs = (LEGlyphID*)alloca( (nGlyphCapacity * nAllocSize) + sizeof(IcuPosition) ); 409 le_int32* pCharIndices = (le_int32*)((char*)pIcuGlyphs + nGlyphCapacity * sizeof(LEGlyphID) ); 410 IcuPosition* pGlyphPositions = (IcuPosition*)((char*)pCharIndices + nGlyphCapacity * sizeof(le_int32) ); 411 412 FreetypeServerFont& rFont = reinterpret_cast<FreetypeServerFont&>(rLayout.GetServerFont()); 413 414 UErrorCode rcI18n = U_ZERO_ERROR; 415 LEErrorCode rcIcu = LE_NO_ERROR; 416 Point aNewPos( 0, 0 ); 417 for( int nGlyphCount = 0;; ) 418 { 419 int nMinRunPos, nEndRunPos; 420 bool bRightToLeft; 421 if( !rArgs.GetNextRun( &nMinRunPos, &nEndRunPos, &bRightToLeft ) ) 422 break; 423 424 // find matching script 425 // TODO: split up bidi run into script runs 426 le_int32 eScriptCode = -1; 427 for( int i = nMinRunPos; i < nEndRunPos; ++i ) 428 { 429 eScriptCode = uscript_getScript( pIcuChars[i], &rcI18n ); 430 if( (eScriptCode > 0) && (eScriptCode != latnScriptCode) ) 431 break; 432 } 433 if( eScriptCode < 0 ) // TODO: handle errors better 434 eScriptCode = latnScriptCode; 435 436 // get layout engine matching to this script 437 // no engine change necessary if script is latin 438 if( !mpIcuLE || ((eScriptCode != meScriptCode) && (eScriptCode > USCRIPT_INHERITED)) ) 439 { 440 // TODO: cache multiple layout engines when multiple scripts are used 441 delete mpIcuLE; 442 meScriptCode = eScriptCode; 443 le_int32 eLangCode = 0; // TODO: get better value 444 mpIcuLE = LayoutEngine::layoutEngineFactory( &maIcuFont, eScriptCode, eLangCode, rcIcu ); 445 if( LE_FAILURE(rcIcu) ) 446 { 447 delete mpIcuLE; 448 mpIcuLE = NULL; 449 } 450 } 451 452 // fall back to default layout if needed 453 if( !mpIcuLE ) 454 break; 455 456 // run ICU layout engine 457 // TODO: get enough context, remove extra glyps below 458 int nRawRunGlyphCount = mpIcuLE->layoutChars( pIcuChars, 459 nMinRunPos, nEndRunPos - nMinRunPos, rArgs.mnLength, 460 bRightToLeft, aNewPos.X(), aNewPos.Y(), rcIcu ); 461 if( LE_FAILURE(rcIcu) ) 462 return false; 463 464 // import layout info from icu 465 mpIcuLE->getGlyphs( pIcuGlyphs, rcIcu ); 466 mpIcuLE->getCharIndices( pCharIndices, rcIcu ); 467 mpIcuLE->getGlyphPositions( &pGlyphPositions->fX, rcIcu ); 468 mpIcuLE->reset(); // TODO: get rid of this, PROBLEM: crash at exit when removed 469 if( LE_FAILURE(rcIcu) ) 470 return false; 471 472 // layout bidi/script runs and export them to a ServerFontLayout 473 // convert results to GlyphItems 474 int nLastCharPos = -1; 475 int nClusterMinPos = -1; 476 int nClusterMaxPos = -1; 477 bool bClusterStart = true; 478 int nFilteredRunGlyphCount = 0; 479 const IcuPosition* pPos = pGlyphPositions; 480 for( int i = 0; i < nRawRunGlyphCount; ++i, ++pPos ) 481 { 482 LEGlyphID nGlyphIndex = pIcuGlyphs[i]; 483 // ignore glyphs which were marked or deleted by ICU 484 if( (nGlyphIndex == ICU_MARKED_GLYPH) 485 || (nGlyphIndex == ICU_DELETED_GLYPH) ) 486 continue; 487 488 // adjust the relative char pos 489 int nCharPos = pCharIndices[i]; 490 if( nCharPos >= 0 ) { 491 nCharPos += nMinRunPos; 492 // ICU seems to return bad pCharIndices 493 // for some combinations of ICU+font+text 494 // => better give up now than crash later 495 if( nCharPos >= nEndRunPos ) 496 continue; 497 } 498 499 // if needed request glyph fallback by updating LayoutArgs 500 if( !nGlyphIndex ) 501 { 502 if( nCharPos >= 0 ) 503 { 504 rArgs.NeedFallback( nCharPos, bRightToLeft ); 505 if ( (nCharPos > 0) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos-1]) ) 506 rArgs.NeedFallback( nCharPos-1, bRightToLeft ); 507 else if ( (nCharPos + 1 < nEndRunPos) && lcl_CharIsJoiner(rArgs.mpStr[nCharPos+1]) ) 508 rArgs.NeedFallback( nCharPos+1, bRightToLeft ); 509 } 510 511 if( SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags ) 512 continue; 513 } 514 515 516 // apply vertical flags, etc. 517 bool bDiacritic = false; 518 if( nCharPos >= 0 ) 519 { 520 sal_UCS4 aChar = rArgs.mpStr[ nCharPos ]; 521 #if 0 // TODO: enable if some unicodes>0xFFFF should need glyph flags!=0 522 if( (aChar >= 0xD800) && (aChar <= 0xDFFF) ) 523 { 524 if( cChar >= 0xDC00 ) // this part of a surrogate pair was already processed 525 continue; 526 // calculate unicode scalar value of surrogate pair 527 aChar = 0x10000 + ((aChar - 0xD800) << 10); 528 sal_UCS4 aLow = rArgs.mpStr[ nCharPos+1 ]; 529 aChar += aLow & 0x03FF; 530 } 531 #endif 532 nGlyphIndex = rFont.FixupGlyphIndex( nGlyphIndex, aChar ); 533 534 // #i99367# HACK: try to detect all diacritics 535 if( aChar>=0x0300 && aChar<0x2100 ) 536 bDiacritic = IsDiacritic( aChar ); 537 } 538 539 // get glyph position and its metrics 540 aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) ); 541 const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex ); 542 int nGlyphWidth = rGM.GetCharWidth(); 543 int nNewWidth = nGlyphWidth; 544 if( nGlyphWidth <= 0 ) 545 bDiacritic |= true; 546 // #i99367# force all diacritics to zero width 547 // TODO: we need mnOrigWidth/mnLogicWidth/mnNewWidth 548 else if( bDiacritic ) 549 nGlyphWidth = nNewWidth = 0; 550 else 551 { 552 // Hack, find next +ve width glyph and calculate current 553 // glyph width by substracting the two posituons 554 const IcuPosition* pNextPos = pPos+1; 555 for ( int j = i + 1; j <= nRawRunGlyphCount; ++j, ++pNextPos ) 556 { 557 if ( j == nRawRunGlyphCount ) 558 { 559 nNewWidth = static_cast<int>(pNextPos->fX - pPos->fX); 560 break; 561 } 562 563 LEGlyphID nNextGlyphIndex = pIcuGlyphs[j]; 564 if( (nNextGlyphIndex == ICU_MARKED_GLYPH) 565 || (nNextGlyphIndex == ICU_DELETED_GLYPH) ) 566 continue; 567 568 const GlyphMetric& rNextGM = rFont.GetGlyphMetric( nNextGlyphIndex ); 569 int nNextGlyphWidth = rNextGM.GetCharWidth(); 570 if ( nNextGlyphWidth > 0 ) 571 { 572 nNewWidth = static_cast<int>(pNextPos->fX - pPos->fX); 573 break; 574 } 575 } 576 } 577 578 // heuristic to detect glyph clusters 579 bool bInCluster = true; 580 if( nLastCharPos == -1 ) 581 { 582 nClusterMinPos = nClusterMaxPos = nCharPos; 583 bInCluster = false; 584 } 585 else if( !bRightToLeft ) 586 { 587 // left-to-right case 588 if( nClusterMinPos > nCharPos ) 589 nClusterMinPos = nCharPos; // extend cluster 590 else if( nCharPos <= nClusterMaxPos ) 591 /*NOTHING*/; // inside cluster 592 else if( bDiacritic ) 593 nClusterMaxPos = nCharPos; // add diacritic to cluster 594 else { 595 nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster 596 bInCluster = false; 597 } 598 } 599 else 600 { 601 // right-to-left case 602 if( nClusterMaxPos < nCharPos ) 603 nClusterMaxPos = nCharPos; // extend cluster 604 else if( nCharPos >= nClusterMinPos ) 605 /*NOTHING*/; // inside cluster 606 else if( bDiacritic ) 607 { 608 nClusterMinPos = nCharPos; // ICU often has [diacritic* baseglyph*] 609 if( bClusterStart ) { 610 nClusterMaxPos = nCharPos; 611 bInCluster = false; 612 } 613 } 614 else 615 { 616 nClusterMinPos = nClusterMaxPos = nCharPos; // new cluster 617 bInCluster = !bClusterStart; 618 } 619 } 620 621 long nGlyphFlags = 0; 622 if( bInCluster ) 623 nGlyphFlags |= GlyphItem::IS_IN_CLUSTER; 624 if( bRightToLeft ) 625 nGlyphFlags |= GlyphItem::IS_RTL_GLYPH; 626 if( bDiacritic ) 627 nGlyphFlags |= GlyphItem::IS_DIACRITIC; 628 629 // add resulting glyph item to layout 630 GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth ); 631 aGI.mnNewWidth = nNewWidth; 632 rLayout.AppendGlyph( aGI ); 633 ++nFilteredRunGlyphCount; 634 nLastCharPos = nCharPos; 635 bClusterStart = !aGI.IsDiacritic(); // TODO: only needed in RTL-codepath 636 } 637 aNewPos = Point( (int)(pPos->fX+0.5), (int)(pPos->fY+0.5) ); 638 nGlyphCount += nFilteredRunGlyphCount; 639 } 640 641 // sort glyphs in visual order 642 // and then in logical order (e.g. diacritics after cluster start) 643 rLayout.SortGlyphItems(); 644 645 // determine need for kashida justification 646 if( (rArgs.mpDXArray || rArgs.mnLayoutWidth) 647 && ((meScriptCode == arabScriptCode) || (meScriptCode == syrcScriptCode)) ) 648 rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON; 649 650 return true; 651 } 652 653 #endif // ENABLE_ICU_LAYOUT 654 655 // ======================================================================= 656 657 ServerFontLayoutEngine* FreetypeServerFont::GetLayoutEngine() 658 { 659 // find best layout engine for font, platform, script and language 660 #ifdef ENABLE_ICU_LAYOUT 661 if( !mpLayoutEngine && FT_IS_SFNT( maFaceFT ) ) 662 mpLayoutEngine = new IcuLayoutEngine( *this ); 663 #endif // ENABLE_ICU_LAYOUT 664 665 return mpLayoutEngine; 666 } 667 668 // ======================================================================= 669 670