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