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 64 U_NAMESPACE_BEGIN 65 66 /* Leave this copyright notice here! It needs to go somewhere in this library. */ 67 static const char copyright[] = U_COPYRIGHT_STRING; 68 69 /* TODO: remove these? */ 70 const le_int32 LayoutEngine::kTypoFlagKern = LE_Kerning_FEATURE_FLAG; 71 const le_int32 LayoutEngine::kTypoFlagLiga = LE_Ligatures_FEATURE_FLAG; 72 73 const 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 80 const le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars); 81 82 const 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 89 const le_int32 DefaultCharMapper::controlCharsZWJCount = LE_ARRAY_SIZE(controlCharsZWJ); 90 91 LEUnicode32 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... 131 LEGlyphFilter::~LEGlyphFilter() 132 { 133 // nothing to do 134 } 135 136 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance) 137 : fFontInstance(fontInstance) 138 { 139 // nothing to do 140 } 141 142 CharSubstitutionFilter::~CharSubstitutionFilter() 143 { 144 // nothing to do 145 } 146 147 class CanonMarkFilter : public UMemory, public LEGlyphFilter 148 { 149 private: 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 155 public: 156 CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success); 157 virtual ~CanonMarkFilter(); 158 159 virtual le_bool accept(LEGlyphID glyph) const; 160 }; 161 162 CanonMarkFilter::CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success) 163 : classDefTable(gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success)) 164 { 165 } 166 167 CanonMarkFilter::~CanonMarkFilter() 168 { 169 // nothing to do? 170 } 171 172 le_bool CanonMarkFilter::accept(LEGlyphID glyph) const 173 { 174 LEErrorCode success = LE_NO_ERROR; 175 le_int32 glyphClass = classDefTable->getGlyphClass(classDefTable, glyph, success); 176 if(LE_FAILURE(success)) return false; 177 return glyphClass != 0; 178 } 179 180 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine) 181 182 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG 183 184 #define ccmpFeatureMask 0x80000000UL 185 186 #define canonFeatures (ccmpFeatureMask) 187 188 static const FeatureMap canonFeatureMap[] = 189 { 190 {ccmpFeatureTag, ccmpFeatureMask} 191 }; 192 193 static const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap); 194 195 LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, 196 le_int32 scriptCode, 197 le_int32 languageCode, 198 le_int32 typoFlags, 199 LEErrorCode &success) 200 : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode), 201 fTypoFlags(typoFlags), fFilterZeroWidth(TRUE) 202 { 203 if (LE_FAILURE(success)) { 204 return; 205 } 206 207 fGlyphStorage = new LEGlyphStorage(); 208 if (fGlyphStorage == NULL) { 209 success = LE_MEMORY_ALLOCATION_ERROR; 210 } 211 } 212 213 le_int32 LayoutEngine::getGlyphCount() const 214 { 215 return fGlyphStorage->getGlyphCount(); 216 } 217 218 void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const 219 { 220 fGlyphStorage->getCharIndices(charIndices, indexBase, success); 221 } 222 223 void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const 224 { 225 fGlyphStorage->getCharIndices(charIndices, success); 226 } 227 228 // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits 229 void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const 230 { 231 fGlyphStorage->getGlyphs(glyphs, extraBits, success); 232 } 233 234 void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const 235 { 236 fGlyphStorage->getGlyphs(glyphs, success); 237 } 238 239 240 void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const 241 { 242 fGlyphStorage->getGlyphPositions(positions, success); 243 } 244 245 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const 246 { 247 fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success); 248 } 249 250 le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, 251 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) 252 { 253 if (LE_FAILURE(success)) { 254 return 0; 255 } 256 257 if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 258 success = LE_ILLEGAL_ARGUMENT_ERROR; 259 return 0; 260 } 261 262 if ((fTypoFlags & LE_NoCanon_FEATURE_FLAG) == 0) { // no canonical processing 263 return count; 264 } 265 266 LEReferenceTo<GlyphSubstitutionTableHeader> canonGSUBTable((GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable); 267 LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); 268 LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); 269 le_int32 i, dir = 1, out = 0, outCharCount = count; 270 271 if (canonGSUBTable->coversScript(canonGSUBTable,scriptTag, success) || LE_SUCCESS(success)) { 272 CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); 273 if (substitutionFilter == NULL) { 274 success = LE_MEMORY_ALLOCATION_ERROR; 275 return 0; 276 } 277 278 const LEUnicode *inChars = &chars[offset]; 279 LEUnicode *reordered = NULL; 280 LEGlyphStorage fakeGlyphStorage; 281 282 fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); 283 284 if (LE_FAILURE(success)) { 285 delete substitutionFilter; 286 return 0; 287 } 288 289 // This is the cheapest way to get mark reordering only for Hebrew. 290 // We could just do the mark reordering for all scripts, but most 291 // of them probably don't need it... 292 if (fScriptCode == hebrScriptCode) { 293 reordered = LE_NEW_ARRAY(LEUnicode, count); 294 295 if (reordered == NULL) { 296 delete substitutionFilter; 297 success = LE_MEMORY_ALLOCATION_ERROR; 298 return 0; 299 } 300 301 CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); 302 inChars = reordered; 303 } 304 305 fakeGlyphStorage.allocateAuxData(success); 306 307 if (LE_FAILURE(success)) { 308 delete substitutionFilter; 309 return 0; 310 } 311 312 if (rightToLeft) { 313 out = count - 1; 314 dir = -1; 315 } 316 317 for (i = 0; i < count; i += 1, out += dir) { 318 fakeGlyphStorage[out] = (LEGlyphID) inChars[i]; 319 fakeGlyphStorage.setAuxData(out, canonFeatures, success); 320 } 321 322 if (reordered != NULL) { 323 LE_DELETE_ARRAY(reordered); 324 } 325 326 outCharCount = canonGSUBTable->process(canonGSUBTable, fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, (const GlyphDefinitionTableHeader*)NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); 327 328 if (LE_FAILURE(success)) { 329 delete substitutionFilter; 330 return 0; 331 } 332 333 out = (rightToLeft? outCharCount - 1 : 0); 334 335 /* 336 * The char indices array in fakeGlyphStorage has the correct mapping 337 * back to the original input characters. Save it in glyphStorage. The 338 * subsequent call to glyphStoratge.allocateGlyphArray will keep this 339 * array rather than allocating and initializing a new one. 340 */ 341 glyphStorage.adoptCharIndicesArray(fakeGlyphStorage); 342 343 outChars = LE_NEW_ARRAY(LEUnicode, outCharCount); 344 345 if (outChars == NULL) { 346 delete substitutionFilter; 347 success = LE_MEMORY_ALLOCATION_ERROR; 348 return 0; 349 } 350 351 for (i = 0; i < outCharCount; i += 1, out += dir) { 352 outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]); 353 } 354 355 delete substitutionFilter; 356 } 357 358 return outCharCount; 359 } 360 361 le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, 362 LEGlyphStorage &glyphStorage, LEErrorCode &success) 363 { 364 if (LE_FAILURE(success)) { 365 return 0; 366 } 367 368 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 369 success = LE_ILLEGAL_ARGUMENT_ERROR; 370 return 0; 371 } 372 373 LEUnicode *outChars = NULL; 374 le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success); 375 376 if (outChars != NULL) { 377 mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success); 378 LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... 379 } else { 380 mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success); 381 } 382 383 return glyphStorage.getGlyphCount(); 384 } 385 386 // Input: glyphs 387 // Output: positions 388 void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success) 389 { 390 if (LE_FAILURE(success)) { 391 return; 392 } 393 394 glyphStorage.allocatePositions(success); 395 396 if (LE_FAILURE(success)) { 397 return; 398 } 399 400 le_int32 i, glyphCount = glyphStorage.getGlyphCount(); 401 402 for (i = 0; i < glyphCount; i += 1) { 403 LEPoint advance; 404 405 glyphStorage.setPosition(i, x, y, success); 406 407 fFontInstance->getGlyphAdvance(glyphStorage[i], advance); 408 x += advance.fX; 409 y += advance.fY; 410 } 411 412 glyphStorage.setPosition(glyphCount, x, y, success); 413 } 414 415 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, 416 LEGlyphStorage &glyphStorage, LEErrorCode &success) 417 { 418 if (LE_FAILURE(success)) { 419 return; 420 } 421 422 if (chars == NULL || offset < 0 || count < 0) { 423 success = LE_ILLEGAL_ARGUMENT_ERROR; 424 return; 425 } 426 427 LEReferenceTo<GlyphDefinitionTableHeader> gdefTable((GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable, 428 CanonShaping::glyphDefinitionTableLen); 429 CanonMarkFilter filter(gdefTable, success); 430 431 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); 432 433 if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ 434 LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); 435 KernTable kt(kernTable, success); 436 kt.process(glyphStorage, success); 437 } 438 439 // default is no adjustments 440 return; 441 } 442 443 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success) 444 { 445 float xAdjust = 0; 446 le_int32 p, glyphCount = glyphStorage.getGlyphCount(); 447 448 if (LE_FAILURE(success)) { 449 return; 450 } 451 452 if (markFilter == NULL) { 453 success = LE_ILLEGAL_ARGUMENT_ERROR; 454 return; 455 } 456 457 float ignore, prev; 458 459 glyphStorage.getGlyphPosition(0, prev, ignore, success); 460 461 for (p = 0; p < glyphCount; p += 1) { 462 float next, xAdvance; 463 464 glyphStorage.getGlyphPosition(p + 1, next, ignore, success); 465 466 xAdvance = next - prev; 467 glyphStorage.adjustPosition(p, xAdjust, 0, success); 468 469 if (markFilter->accept(glyphStorage[p])) { 470 xAdjust -= xAdvance; 471 } 472 473 prev = next; 474 } 475 476 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); 477 } 478 479 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success) 480 { 481 float xAdjust = 0; 482 le_int32 c = 0, direction = 1, p; 483 le_int32 glyphCount = glyphStorage.getGlyphCount(); 484 485 if (LE_FAILURE(success)) { 486 return; 487 } 488 489 if (markFilter == NULL) { 490 success = LE_ILLEGAL_ARGUMENT_ERROR; 491 return; 492 } 493 494 if (reverse) { 495 c = glyphCount - 1; 496 direction = -1; 497 } 498 499 float ignore, prev; 500 501 glyphStorage.getGlyphPosition(0, prev, ignore, success); 502 503 for (p = 0; p < charCount; p += 1, c += direction) { 504 float next, xAdvance; 505 506 glyphStorage.getGlyphPosition(p + 1, next, ignore, success); 507 508 xAdvance = next - prev; 509 glyphStorage.adjustPosition(p, xAdjust, 0, success); 510 511 if (markFilter->accept(chars[c])) { 512 xAdjust -= xAdvance; 513 } 514 515 prev = next; 516 } 517 518 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); 519 } 520 521 const void *LayoutEngine::getFontTable(LETag tableTag, size_t &length) const 522 { 523 return fFontInstance->getFontTable(tableTag, length); 524 } 525 526 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, 527 LEGlyphStorage &glyphStorage, LEErrorCode &success) 528 { 529 if (LE_FAILURE(success)) { 530 return; 531 } 532 533 glyphStorage.allocateGlyphArray(count, reverse, success); 534 535 DefaultCharMapper charMapper(TRUE, mirror); 536 537 fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, fFilterZeroWidth, glyphStorage); 538 } 539 540 // Input: characters, font? 541 // Output: glyphs, positions, char indices 542 // Returns: number of glyphs 543 le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, 544 float x, float y, LEErrorCode &success) 545 { 546 if (LE_FAILURE(success)) { 547 return 0; 548 } 549 550 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 551 success = LE_ILLEGAL_ARGUMENT_ERROR; 552 return 0; 553 } 554 555 le_int32 glyphCount; 556 557 if (fGlyphStorage->getGlyphCount() > 0) { 558 fGlyphStorage->reset(); 559 } 560 561 glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success); 562 positionGlyphs(*fGlyphStorage, x, y, success); 563 adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success); 564 565 return glyphCount; 566 } 567 568 void LayoutEngine::reset() 569 { 570 if(fGlyphStorage!=NULL) { 571 fGlyphStorage->reset(); 572 fGlyphStorage = NULL; 573 } 574 } 575 576 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success) 577 { 578 //kerning and ligatures - by default 579 return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, LE_DEFAULT_FEATURE_FLAG, success); 580 } 581 582 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) 583 { 584 static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG; 585 static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG; 586 static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG; 587 588 if (LE_FAILURE(success)) { 589 return NULL; 590 } 591 592 LEReferenceTo<GlyphSubstitutionTableHeader> gsubTable(fontInstance,gsubTableTag,success); 593 LayoutEngine *result = NULL; 594 LETag scriptTag = 0x00000000; 595 LETag languageTag = 0x00000000; 596 LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); 597 598 // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are 599 // properly tested. 600 601 if ( v2ScriptTag == dev2ScriptTag && gsubTable.isValid() && gsubTable->coversScript(gsubTable, v2ScriptTag, success )) { 602 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); 603 } 604 else if (gsubTable.isValid() && gsubTable->coversScript(gsubTable, scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode), success)) { 605 switch (scriptCode) { 606 case bengScriptCode: 607 case devaScriptCode: 608 case gujrScriptCode: 609 case kndaScriptCode: 610 case mlymScriptCode: 611 case oryaScriptCode: 612 case guruScriptCode: 613 case tamlScriptCode: 614 case teluScriptCode: 615 case sinhScriptCode: 616 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success); 617 break; 618 619 case arabScriptCode: 620 result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 621 break; 622 623 case hebrScriptCode: 624 // Disable hebrew ligatures since they have only archaic uses, see ticket #8318 625 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success); 626 break; 627 628 case hangScriptCode: 629 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 630 break; 631 632 case haniScriptCode: 633 languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode); 634 635 switch (languageCode) { 636 case korLanguageCode: 637 case janLanguageCode: 638 case zhtLanguageCode: 639 case zhsLanguageCode: 640 if (gsubTable->coversScriptAndLanguage(gsubTable, scriptTag, languageTag, success, TRUE)) { 641 result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 642 break; 643 } 644 645 // note: falling through to default case. 646 default: 647 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 648 break; 649 } 650 651 break; 652 653 case tibtScriptCode: 654 result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 655 break; 656 657 case khmrScriptCode: 658 result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 659 break; 660 661 default: 662 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 663 break; 664 } 665 } else { 666 MorphTableHeader2 *morxTable = (MorphTableHeader2 *)fontInstance->getFontTable(morxTableTag); 667 if (morxTable != NULL && SWAPL(morxTable->version)==0x00020000) { 668 result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); 669 } else { 670 LEReferenceTo<MorphTableHeader> mortTable(fontInstance, mortTableTag, success); 671 if (LE_SUCCESS(success) && mortTable.isValid() && SWAPL(mortTable->version)==0x00010000) { // mort 672 result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); 673 } else { 674 switch (scriptCode) { 675 case bengScriptCode: 676 case devaScriptCode: 677 case gujrScriptCode: 678 case kndaScriptCode: 679 case mlymScriptCode: 680 case oryaScriptCode: 681 case guruScriptCode: 682 case tamlScriptCode: 683 case teluScriptCode: 684 case sinhScriptCode: 685 { 686 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 687 break; 688 } 689 690 case arabScriptCode: 691 //case hebrScriptCode: 692 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 693 break; 694 695 //case hebrScriptCode: 696 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); 697 698 case thaiScriptCode: 699 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 700 break; 701 702 case hangScriptCode: 703 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 704 break; 705 706 default: 707 result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 708 break; 709 } 710 } 711 } 712 } 713 714 if (result && LE_FAILURE(success)) { 715 delete result; 716 result = NULL; 717 } 718 719 if (result == NULL) { 720 success = LE_MEMORY_ALLOCATION_ERROR; 721 } 722 723 return result; 724 } 725 726 LayoutEngine::~LayoutEngine() { 727 delete fGlyphStorage; 728 } 729 730 U_NAMESPACE_END