1/* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 27/* 28 * 29 * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved 30 * 31 */ 32 33#include "LETypes.h" 34#include "LEScripts.h" 35#include "LELanguages.h" 36#include "LESwaps.h" 37 38#include "LayoutEngine.h" 39#include "ArabicLayoutEngine.h" 40#include "CanonShaping.h" 41#include "HanLayoutEngine.h" 42#include "HangulLayoutEngine.h" 43#include "IndicLayoutEngine.h" 44#include "KhmerLayoutEngine.h" 45#include "ThaiLayoutEngine.h" 46#include "TibetanLayoutEngine.h" 47#include "GXLayoutEngine.h" 48#include "GXLayoutEngine2.h" 49 50#include "ScriptAndLanguageTags.h" 51#include "CharSubstitutionFilter.h" 52 53#include "LEGlyphStorage.h" 54 55#include "OpenTypeUtilities.h" 56#include "GlyphSubstitutionTables.h" 57#include "GlyphDefinitionTables.h" 58#include "MorphTables.h" 59 60#include "DefaultCharMapper.h" 61 62#include "KernTable.h" 63 64U_NAMESPACE_BEGIN 65 66/* Leave this copyright notice here! It needs to go somewhere in this library. */ 67static const char copyright[] = U_COPYRIGHT_STRING; 68 69/* TODO: remove these? */ 70const le_int32 LayoutEngine::kTypoFlagKern = LE_Kerning_FEATURE_FLAG; 71const le_int32 LayoutEngine::kTypoFlagLiga = LE_Ligatures_FEATURE_FLAG; 72 73const LEUnicode32 DefaultCharMapper::controlChars[] = { 74 0x0009, 0x000A, 0x000D, 75 /*0x200C, 0x200D,*/ 0x200E, 0x200F, 76 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, 77 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F 78}; 79 80const le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars); 81 82const LEUnicode32 DefaultCharMapper::controlCharsZWJ[] = { 83 0x0009, 0x000A, 0x000D, 84 0x200C, 0x200D, 0x200E, 0x200F, 85 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, 86 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F 87}; 88 89const le_int32 DefaultCharMapper::controlCharsZWJCount = LE_ARRAY_SIZE(controlCharsZWJ); 90 91LEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch) const 92{ 93 if (fZWJ) { 94 if (ch < 0x20) { 95 if (ch == 0x0a || ch == 0x0d || ch == 0x09) { 96 return 0xffff; 97 } 98 } else if (ch >= 0x200c && ch <= 0x206f) { 99 le_int32 index = OpenTypeUtilities::search((le_uint32)ch, 100 (le_uint32 *)controlCharsZWJ, 101 controlCharsZWJCount); 102 if (controlCharsZWJ[index] == ch) { 103 return 0xffff; 104 } 105 } 106 return ch; // note ZWJ bypasses fFilterControls and fMirror 107 } 108 109 if (fFilterControls) { 110 le_int32 index = OpenTypeUtilities::search((le_uint32)ch, (le_uint32 *)controlChars, controlCharsCount); 111 112 if (controlChars[index] == ch) { 113 return 0xFFFF; 114 } 115 } 116 117 if (fMirror) { 118 le_int32 index = OpenTypeUtilities::search((le_uint32) ch, (le_uint32 *)DefaultCharMapper::mirroredChars, DefaultCharMapper::mirroredCharsCount); 119 120 if (mirroredChars[index] == ch) { 121 return DefaultCharMapper::srahCderorrim[index]; 122 } 123 } 124 125 return ch; 126} 127 128// This is here to get it out of LEGlyphFilter.h. 129// No particular reason to put it here, other than 130// this is a good central location... 131LEGlyphFilter::~LEGlyphFilter() 132{ 133 // nothing to do 134} 135 136CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance) 137 : fFontInstance(fontInstance) 138{ 139 // nothing to do 140} 141 142CharSubstitutionFilter::~CharSubstitutionFilter() 143{ 144 // nothing to do 145} 146 147class CanonMarkFilter : public UMemory, public LEGlyphFilter 148{ 149private: 150 const LEReferenceTo<GlyphClassDefinitionTable> classDefTable; 151 152 CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class 153 CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class 154 155public: 156 CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success); 157 virtual ~CanonMarkFilter(); 158 159 virtual le_bool accept(LEGlyphID glyph, LEErrorCode &success) const; 160}; 161 162CanonMarkFilter::CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success) 163 : classDefTable(gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success)) 164{ 165} 166 167CanonMarkFilter::~CanonMarkFilter() 168{ 169 // nothing to do? 170} 171 172le_bool CanonMarkFilter::accept(LEGlyphID glyph, LEErrorCode &success) const 173{ 174 le_int32 glyphClass = classDefTable->getGlyphClass(classDefTable, glyph, success); 175 if(LE_FAILURE(success)) return false; 176 return glyphClass != 0; 177} 178 179UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine) 180 181#define ccmpFeatureTag LE_CCMP_FEATURE_TAG 182 183#define ccmpFeatureMask 0x80000000UL 184 185#define canonFeatures (ccmpFeatureMask) 186 187static const FeatureMap canonFeatureMap[] = 188{ 189 {ccmpFeatureTag, ccmpFeatureMask} 190}; 191 192static const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap); 193 194LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, 195 le_int32 scriptCode, 196 le_int32 languageCode, 197 le_int32 typoFlags, 198 LEErrorCode &success) 199 : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode), 200 fTypoFlags(typoFlags), fFilterZeroWidth(TRUE) 201{ 202 if (LE_FAILURE(success)) { 203 return; 204 } 205 206 fGlyphStorage = new LEGlyphStorage(); 207 if (fGlyphStorage == NULL) { 208 success = LE_MEMORY_ALLOCATION_ERROR; 209 } 210} 211 212le_int32 LayoutEngine::getGlyphCount() const 213{ 214 return fGlyphStorage->getGlyphCount(); 215} 216 217void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const 218{ 219 fGlyphStorage->getCharIndices(charIndices, indexBase, success); 220} 221 222void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const 223{ 224 fGlyphStorage->getCharIndices(charIndices, success); 225} 226 227// Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits 228void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const 229{ 230 fGlyphStorage->getGlyphs(glyphs, extraBits, success); 231} 232 233void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const 234{ 235 fGlyphStorage->getGlyphs(glyphs, success); 236} 237 238 239void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const 240{ 241 fGlyphStorage->getGlyphPositions(positions, success); 242} 243 244void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const 245{ 246 fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success); 247} 248 249le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, 250 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) 251{ 252 if (LE_FAILURE(success)) { 253 return 0; 254 } 255 256 if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 257 success = LE_ILLEGAL_ARGUMENT_ERROR; 258 return 0; 259 } 260 261 if ((fTypoFlags & LE_NoCanon_FEATURE_FLAG) == 0) { // no canonical processing 262 return count; 263 } 264 265 LEReferenceTo<GlyphSubstitutionTableHeader> canonGSUBTable(LETableReference::kStaticData, 266 (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable, 267 CanonShaping::glyphSubstitutionTableLen); 268 LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); 269 LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); 270 le_int32 i, dir = 1, out = 0, outCharCount = count; 271 272 if (canonGSUBTable->coversScript(canonGSUBTable,scriptTag, success) || LE_SUCCESS(success)) { 273 CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); 274 if (substitutionFilter == NULL) { 275 success = LE_MEMORY_ALLOCATION_ERROR; 276 return 0; 277 } 278 279 const LEUnicode *inChars = &chars[offset]; 280 LEUnicode *reordered = NULL; 281 LEGlyphStorage fakeGlyphStorage; 282 283 fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); 284 285 if (LE_FAILURE(success)) { 286 delete substitutionFilter; 287 return 0; 288 } 289 290 // This is the cheapest way to get mark reordering only for Hebrew. 291 // We could just do the mark reordering for all scripts, but most 292 // of them probably don't need it... 293 if (fScriptCode == hebrScriptCode) { 294 reordered = LE_NEW_ARRAY(LEUnicode, count); 295 296 if (reordered == NULL) { 297 delete substitutionFilter; 298 success = LE_MEMORY_ALLOCATION_ERROR; 299 return 0; 300 } 301 302 CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); 303 inChars = reordered; 304 } 305 306 fakeGlyphStorage.allocateAuxData(success); 307 308 if (LE_FAILURE(success)) { 309 delete substitutionFilter; 310 return 0; 311 } 312 313 if (rightToLeft) { 314 out = count - 1; 315 dir = -1; 316 } 317 318 for (i = 0; i < count; i += 1, out += dir) { 319 fakeGlyphStorage[out] = (LEGlyphID) inChars[i]; 320 fakeGlyphStorage.setAuxData(out, canonFeatures, success); 321 } 322 323 if (reordered != NULL) { 324 LE_DELETE_ARRAY(reordered); 325 } 326 327 const LEReferenceTo<GlyphDefinitionTableHeader> noGDEF; // empty gdef header 328 outCharCount = canonGSUBTable->process(canonGSUBTable, fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, noGDEF, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); 329 330 if (LE_FAILURE(success)) { 331 delete substitutionFilter; 332 return 0; 333 } 334 335 out = (rightToLeft? outCharCount - 1 : 0); 336 337 /* 338 * The char indices array in fakeGlyphStorage has the correct mapping 339 * back to the original input characters. Save it in glyphStorage. The 340 * subsequent call to glyphStoratge.allocateGlyphArray will keep this 341 * array rather than allocating and initializing a new one. 342 */ 343 glyphStorage.adoptCharIndicesArray(fakeGlyphStorage); 344 345 outChars = LE_NEW_ARRAY(LEUnicode, outCharCount); 346 347 if (outChars == NULL) { 348 delete substitutionFilter; 349 success = LE_MEMORY_ALLOCATION_ERROR; 350 return 0; 351 } 352 353 for (i = 0; i < outCharCount; i += 1, out += dir) { 354 outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]); 355 } 356 357 delete substitutionFilter; 358 } 359 360 return outCharCount; 361} 362 363le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, 364 LEGlyphStorage &glyphStorage, LEErrorCode &success) 365{ 366 if (LE_FAILURE(success)) { 367 return 0; 368 } 369 370 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 371 success = LE_ILLEGAL_ARGUMENT_ERROR; 372 return 0; 373 } 374 375 LEUnicode *outChars = NULL; 376 le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success); 377 378 if (outChars != NULL) { 379 mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success); 380 LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... 381 } else { 382 mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success); 383 } 384 385 return glyphStorage.getGlyphCount(); 386} 387 388// Input: glyphs 389// Output: positions 390void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success) 391{ 392 if (LE_FAILURE(success)) { 393 return; 394 } 395 396 glyphStorage.allocatePositions(success); 397 398 if (LE_FAILURE(success)) { 399 return; 400 } 401 402 le_int32 i, glyphCount = glyphStorage.getGlyphCount(); 403 404 for (i = 0; i < glyphCount; i += 1) { 405 LEPoint advance; 406 407 glyphStorage.setPosition(i, x, y, success); 408 _LETRACE("g#%-4d (%.2f, %.2f)", i, x, y); 409 410 fFontInstance->getGlyphAdvance(glyphStorage[i], advance); 411 x += advance.fX; 412 y += advance.fY; 413 414 415 } 416 417 glyphStorage.setPosition(glyphCount, x, y, success); 418} 419 420void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, 421 LEGlyphStorage &glyphStorage, LEErrorCode &success) 422{ 423 if (LE_FAILURE(success)) { 424 return; 425 } 426 427 if (chars == NULL || offset < 0 || count < 0) { 428 success = LE_ILLEGAL_ARGUMENT_ERROR; 429 return; 430 } 431 432 LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(LETableReference::kStaticData, (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable, 433 CanonShaping::glyphDefinitionTableLen); 434 CanonMarkFilter filter(gdefTable, success); 435 436 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); 437 438 if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ 439 LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); 440 KernTable kt(kernTable, success); 441 kt.process(glyphStorage, success); 442 } 443 444 // default is no adjustments 445 return; 446} 447 448void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success) 449{ 450 float xAdjust = 0; 451 le_int32 p, glyphCount = glyphStorage.getGlyphCount(); 452 453 if (LE_FAILURE(success)) { 454 return; 455 } 456 457 if (markFilter == NULL) { 458 success = LE_ILLEGAL_ARGUMENT_ERROR; 459 return; 460 } 461 462 float ignore, prev; 463 464 glyphStorage.getGlyphPosition(0, prev, ignore, success); 465 466 for (p = 0; p < glyphCount; p += 1) { 467 float next, xAdvance; 468 469 glyphStorage.getGlyphPosition(p + 1, next, ignore, success); 470 471 xAdvance = next - prev; 472 _LETRACE("p#%d (%.2f,%.2f)", p, xAdvance, 0); 473 glyphStorage.adjustPosition(p, xAdjust, 0, success); 474 475 if (markFilter->accept(glyphStorage[p], success)) { 476 xAdjust -= xAdvance; 477 } 478 479 prev = next; 480 } 481 482 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); 483} 484 485void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success) 486{ 487 float xAdjust = 0; 488 le_int32 c = 0, direction = 1, p; 489 le_int32 glyphCount = glyphStorage.getGlyphCount(); 490 491 if (LE_FAILURE(success)) { 492 return; 493 } 494 495 if (markFilter == NULL) { 496 success = LE_ILLEGAL_ARGUMENT_ERROR; 497 return; 498 } 499 500 if (reverse) { 501 c = glyphCount - 1; 502 direction = -1; 503 } 504 505 float ignore, prev; 506 507 glyphStorage.getGlyphPosition(0, prev, ignore, success); 508 509 for (p = 0; p < charCount; p += 1, c += direction) { 510 float next, xAdvance; 511 512 glyphStorage.getGlyphPosition(p + 1, next, ignore, success); 513 514 xAdvance = next - prev; 515 516 _LETRACE("p#%d (%.2f,%.2f)", p, xAdvance, 0); 517 518 519 glyphStorage.adjustPosition(p, xAdjust, 0, success); 520 521 if (markFilter->accept(chars[c], success)) { 522 xAdjust -= xAdvance; 523 } 524 525 prev = next; 526 } 527 528 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); 529} 530 531const void *LayoutEngine::getFontTable(LETag tableTag, size_t &length) const 532{ 533 return fFontInstance->getFontTable(tableTag, length); 534} 535 536void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, 537 LEGlyphStorage &glyphStorage, LEErrorCode &success) 538{ 539 if (LE_FAILURE(success)) { 540 return; 541 } 542 543 glyphStorage.allocateGlyphArray(count, reverse, success); 544 545 DefaultCharMapper charMapper(TRUE, mirror); 546 547 fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, fFilterZeroWidth, glyphStorage); 548} 549 550// Input: characters, font? 551// Output: glyphs, positions, char indices 552// Returns: number of glyphs 553le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, 554 float x, float y, LEErrorCode &success) 555{ 556 if (LE_FAILURE(success)) { 557 return 0; 558 } 559 560 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 561 success = LE_ILLEGAL_ARGUMENT_ERROR; 562 return 0; 563 } 564 565 le_int32 glyphCount; 566 567 if (fGlyphStorage->getGlyphCount() > 0) { 568 fGlyphStorage->reset(); 569 } 570 571 glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success); 572 positionGlyphs(*fGlyphStorage, x, y, success); 573 adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success); 574 575 return glyphCount; 576} 577 578void LayoutEngine::reset() 579{ 580 if(fGlyphStorage!=NULL) { 581 fGlyphStorage->reset(); 582 } 583} 584 585LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success) 586{ 587 //kerning and ligatures - by default 588 return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, LE_DEFAULT_FEATURE_FLAG, success); 589} 590 591LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) 592{ 593 static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG; 594 static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG; 595 static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG; 596 597 if (LE_FAILURE(success)) { 598 return NULL; 599 } 600 601 LEReferenceTo<GlyphSubstitutionTableHeader> gsubTable(fontInstance,gsubTableTag,success); 602 LayoutEngine *result = NULL; 603 LETag scriptTag = 0x00000000; 604 LETag languageTag = 0x00000000; 605 LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); 606 607 // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are 608 // properly tested. 609 610 if ( v2ScriptTag == dev2ScriptTag && gsubTable.isValid() && gsubTable->coversScript(gsubTable, v2ScriptTag, success )) { 611 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); 612 } 613 else if (gsubTable.isValid() && gsubTable->coversScript(gsubTable, scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode), success)) { 614 switch (scriptCode) { 615 case bengScriptCode: 616 case devaScriptCode: 617 case gujrScriptCode: 618 case kndaScriptCode: 619 case mlymScriptCode: 620 case oryaScriptCode: 621 case guruScriptCode: 622 case tamlScriptCode: 623 case teluScriptCode: 624 case sinhScriptCode: 625 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success); 626 break; 627 628 case arabScriptCode: 629 result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 630 break; 631 632 case hebrScriptCode: 633 // Disable hebrew ligatures since they have only archaic uses, see ticket #8318 634 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success); 635 break; 636 637 case hangScriptCode: 638 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 639 break; 640 641 case haniScriptCode: 642 languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode); 643 644 switch (languageCode) { 645 case korLanguageCode: 646 case janLanguageCode: 647 case zhtLanguageCode: 648 case zhsLanguageCode: 649 if (gsubTable->coversScriptAndLanguage(gsubTable, scriptTag, languageTag, success, TRUE)) { 650 result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 651 break; 652 } 653 654 // note: falling through to default case. 655 default: 656 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 657 break; 658 } 659 660 break; 661 662 case tibtScriptCode: 663 result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 664 break; 665 666 case khmrScriptCode: 667 result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 668 break; 669 670 default: 671 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 672 break; 673 } 674 } else { 675 LEReferenceTo<MorphTableHeader2> morxTable(fontInstance, morxTableTag, success); 676 if (LE_SUCCESS(success) && 677 morxTable.isValid() && 678 SWAPL(morxTable->version)==0x00020000) { 679 result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); 680 } else { 681 LEReferenceTo<MorphTableHeader> mortTable(fontInstance, mortTableTag, success); 682 if (LE_SUCCESS(success) && mortTable.isValid() && SWAPL(mortTable->version)==0x00010000) { // mort 683 result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); 684 } else { 685 switch (scriptCode) { 686 case bengScriptCode: 687 case devaScriptCode: 688 case gujrScriptCode: 689 case kndaScriptCode: 690 case mlymScriptCode: 691 case oryaScriptCode: 692 case guruScriptCode: 693 case tamlScriptCode: 694 case teluScriptCode: 695 case sinhScriptCode: 696 { 697 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 698 break; 699 } 700 701 case arabScriptCode: 702 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 703 break; 704 705 //case hebrScriptCode: 706 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); 707 708 case thaiScriptCode: 709 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 710 break; 711 712 case hangScriptCode: 713 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 714 break; 715 716 default: 717 result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 718 break; 719 } 720 } 721 } 722 } 723 724 if (result && LE_FAILURE(success)) { 725 delete result; 726 result = NULL; 727 } 728 729 if (result == NULL) { 730 success = LE_MEMORY_ALLOCATION_ERROR; 731 } 732 733 return result; 734} 735 736LayoutEngine::~LayoutEngine() { 737 delete fGlyphStorage; 738} 739 740U_NAMESPACE_END 741