Home | History | Annotate | Download | only in layout
      1 
      2 /*
      3  *
      4  * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved
      5  *
      6  */
      7 
      8 #include "LETypes.h"
      9 #include "LEScripts.h"
     10 #include "LELanguages.h"
     11 
     12 #include "LayoutEngine.h"
     13 #include "ArabicLayoutEngine.h"
     14 #include "CanonShaping.h"
     15 #include "HanLayoutEngine.h"
     16 #include "HangulLayoutEngine.h"
     17 #include "IndicLayoutEngine.h"
     18 #include "KhmerLayoutEngine.h"
     19 #include "ThaiLayoutEngine.h"
     20 #include "TibetanLayoutEngine.h"
     21 #include "GXLayoutEngine.h"
     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 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 hangScriptCode:
    558             result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
    559             break;
    560 
    561         case haniScriptCode:
    562             languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
    563 
    564             switch (languageCode) {
    565             case korLanguageCode:
    566             case janLanguageCode:
    567             case zhtLanguageCode:
    568             case zhsLanguageCode:
    569                 if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) {
    570                     result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
    571                     break;
    572                 }
    573 
    574                 // note: falling through to default case.
    575             default:
    576                 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
    577                 break;
    578             }
    579 
    580             break;
    581 
    582         case tibtScriptCode:
    583             result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
    584             break;
    585 
    586         case khmrScriptCode:
    587             result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
    588             break;
    589 
    590         default:
    591             result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
    592             break;
    593         }
    594     } else {
    595         const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag);
    596 
    597         if (morphTable != NULL) {
    598             result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable, success);
    599         } else {
    600             switch (scriptCode) {
    601             case bengScriptCode:
    602             case devaScriptCode:
    603             case gujrScriptCode:
    604             case kndaScriptCode:
    605             case mlymScriptCode:
    606             case oryaScriptCode:
    607             case guruScriptCode:
    608             case tamlScriptCode:
    609             case teluScriptCode:
    610             case sinhScriptCode:
    611             {
    612                 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
    613                 break;
    614             }
    615 
    616             case arabScriptCode:
    617             //case hebrScriptCode:
    618                 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
    619                 break;
    620 
    621             //case hebrScriptCode:
    622             //    return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
    623 
    624             case thaiScriptCode:
    625                 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
    626                 break;
    627 
    628             case hangScriptCode:
    629                 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
    630                 break;
    631 
    632             default:
    633                 result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
    634                 break;
    635             }
    636         }
    637     }
    638 
    639     if (result && LE_FAILURE(success)) {
    640 		delete result;
    641 		result = NULL;
    642 	}
    643 
    644     if (result == NULL) {
    645         success = LE_MEMORY_ALLOCATION_ERROR;
    646     }
    647 
    648     return result;
    649 }
    650 
    651 LayoutEngine::~LayoutEngine() {
    652     delete fGlyphStorage;
    653 }
    654 
    655 U_NAMESPACE_END
    656