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