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 } 573 } 574 575 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success) 576 { 577 //kerning and ligatures - by default 578 return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, LE_DEFAULT_FEATURE_FLAG, success); 579 } 580 581 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) 582 { 583 static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG; 584 static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG; 585 static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG; 586 587 if (LE_FAILURE(success)) { 588 return NULL; 589 } 590 591 LEReferenceTo<GlyphSubstitutionTableHeader> gsubTable(fontInstance,gsubTableTag,success); 592 LayoutEngine *result = NULL; 593 LETag scriptTag = 0x00000000; 594 LETag languageTag = 0x00000000; 595 LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); 596 597 // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are 598 // properly tested. 599 600 if ( v2ScriptTag == dev2ScriptTag && gsubTable.isValid() && gsubTable->coversScript(gsubTable, v2ScriptTag, success )) { 601 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); 602 } 603 else if (gsubTable.isValid() && gsubTable->coversScript(gsubTable, scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode), success)) { 604 switch (scriptCode) { 605 case bengScriptCode: 606 case devaScriptCode: 607 case gujrScriptCode: 608 case kndaScriptCode: 609 case mlymScriptCode: 610 case oryaScriptCode: 611 case guruScriptCode: 612 case tamlScriptCode: 613 case teluScriptCode: 614 case sinhScriptCode: 615 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success); 616 break; 617 618 case arabScriptCode: 619 result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 620 break; 621 622 case hebrScriptCode: 623 // Disable hebrew ligatures since they have only archaic uses, see ticket #8318 624 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success); 625 break; 626 627 case hangScriptCode: 628 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 629 break; 630 631 case haniScriptCode: 632 languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode); 633 634 switch (languageCode) { 635 case korLanguageCode: 636 case janLanguageCode: 637 case zhtLanguageCode: 638 case zhsLanguageCode: 639 if (gsubTable->coversScriptAndLanguage(gsubTable, scriptTag, languageTag, success, TRUE)) { 640 result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 641 break; 642 } 643 644 // note: falling through to default case. 645 default: 646 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 647 break; 648 } 649 650 break; 651 652 case tibtScriptCode: 653 result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 654 break; 655 656 case khmrScriptCode: 657 result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 658 break; 659 660 default: 661 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); 662 break; 663 } 664 } else { 665 MorphTableHeader2 *morxTable = (MorphTableHeader2 *)fontInstance->getFontTable(morxTableTag); 666 if (morxTable != NULL && SWAPL(morxTable->version)==0x00020000) { 667 result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); 668 } else { 669 LEReferenceTo<MorphTableHeader> mortTable(fontInstance, mortTableTag, success); 670 if (LE_SUCCESS(success) && mortTable.isValid() && SWAPL(mortTable->version)==0x00010000) { // mort 671 result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); 672 } else { 673 switch (scriptCode) { 674 case bengScriptCode: 675 case devaScriptCode: 676 case gujrScriptCode: 677 case kndaScriptCode: 678 case mlymScriptCode: 679 case oryaScriptCode: 680 case guruScriptCode: 681 case tamlScriptCode: 682 case teluScriptCode: 683 case sinhScriptCode: 684 { 685 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 686 break; 687 } 688 689 case arabScriptCode: 690 //case hebrScriptCode: 691 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 692 break; 693 694 //case hebrScriptCode: 695 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); 696 697 case thaiScriptCode: 698 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 699 break; 700 701 case hangScriptCode: 702 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 703 break; 704 705 default: 706 result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); 707 break; 708 } 709 } 710 } 711 } 712 713 if (result && LE_FAILURE(success)) { 714 delete result; 715 result = NULL; 716 } 717 718 if (result == NULL) { 719 success = LE_MEMORY_ALLOCATION_ERROR; 720 } 721 722 return result; 723 } 724 725 LayoutEngine::~LayoutEngine() { 726 delete fGlyphStorage; 727 } 728 729 U_NAMESPACE_END