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