fontservices/textshaperplugin/IcuSource/layout/LayoutEngine.cpp
changeset 0 1fb32624e06b
equal deleted inserted replaced
-1:000000000000 0:1fb32624e06b
       
     1 
       
     2 /*
       
     3  *
       
     4  * (C) Copyright IBM Corp. 1998-2005 - 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 "IndicLayoutEngine.h"
       
    17 #include "KhmerLayoutEngine.h"
       
    18 #include "ThaiLayoutEngine.h"
       
    19 #include "GXLayoutEngine.h"
       
    20 #include "ScriptAndLanguageTags.h"
       
    21 #include "CharSubstitutionFilter.h"
       
    22 
       
    23 #include "LEGlyphStorage.h"
       
    24 
       
    25 #include "OpenTypeUtilities.h"
       
    26 #include "GlyphSubstitutionTables.h"
       
    27 #include "MorphTables.h"
       
    28 
       
    29 #include "DefaultCharMapper.h"
       
    30 
       
    31 #include "KernTable.h"
       
    32 
       
    33 U_NAMESPACE_BEGIN
       
    34 
       
    35 #define ARRAY_SIZE(array) (sizeof array  / sizeof array[0])
       
    36 
       
    37 const LEUnicode32 DefaultCharMapper::controlChars[] = {
       
    38     0x0009, 0x000A, 0x000D,
       
    39     /*0x200C, 0x200D,*/ 0x200E, 0x200F,
       
    40     0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
       
    41     0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
       
    42 };
       
    43 
       
    44 const le_int32 DefaultCharMapper::controlCharsCount = ARRAY_SIZE(controlChars);
       
    45 
       
    46 const LEUnicode32 DefaultCharMapper::mirroredChars[] = {
       
    47     0x0028, 0x0029, // ascii paired punctuation
       
    48     0x003c, 0x003e,
       
    49     0x005b, 0x005d,
       
    50     0x007b, 0x007d,
       
    51     0x2045, 0x2046, // math symbols (not complete)
       
    52     0x207d, 0x207e,
       
    53     0x208d, 0x208e,
       
    54     0x2264, 0x2265,
       
    55     0x3008, 0x3009, // chinese paired punctuation
       
    56     0x300a, 0x300b,
       
    57     0x300c, 0x300d,
       
    58     0x300e, 0x300f,
       
    59     0x3010, 0x3011,
       
    60     0x3014, 0x3015,
       
    61     0x3016, 0x3017,
       
    62     0x3018, 0x3019,
       
    63     0x301a, 0x301b
       
    64 };
       
    65 
       
    66 const le_int32 DefaultCharMapper::mirroredCharsCount = ARRAY_SIZE(mirroredChars);
       
    67 
       
    68 LEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch) const
       
    69 {
       
    70     if (fFilterControls) {
       
    71         le_int32 index = OpenTypeUtilities::search((le_uint32)ch, (le_uint32 *)controlChars, controlCharsCount);
       
    72 
       
    73         if (controlChars[index] == ch) {
       
    74             return 0xFFFF;
       
    75         }
       
    76     }
       
    77 
       
    78     if (fMirror) {
       
    79         le_int32 index = OpenTypeUtilities::search((le_uint32) ch, (le_uint32 *)mirroredChars, mirroredCharsCount);
       
    80 
       
    81         if (mirroredChars[index] == ch) {
       
    82             le_int32 mirrorOffset = ((index & 1) == 0) ? 1 : -1;
       
    83 
       
    84             return mirroredChars[index + mirrorOffset];
       
    85         }
       
    86     }
       
    87 
       
    88     return ch;
       
    89 }
       
    90 
       
    91 // This is here to get it out of LEGlyphFilter.h.
       
    92 // No particular reason to put it here, other than
       
    93 // this is a good central location...
       
    94 LEGlyphFilter::~LEGlyphFilter()
       
    95 {
       
    96     // nothing to do
       
    97 }
       
    98 
       
    99 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance)
       
   100   : fFontInstance(fontInstance)
       
   101 {
       
   102     // nothing to do
       
   103 }
       
   104 
       
   105 CharSubstitutionFilter::~CharSubstitutionFilter()
       
   106 {
       
   107     // nothing to do
       
   108 }
       
   109 
       
   110 
       
   111 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine)
       
   112 
       
   113 static const LETag emptyTag = 0x00000000;
       
   114 
       
   115 static const LETag ccmpFeatureTag = LE_CCMP_FEATURE_TAG;
       
   116 
       
   117 static const LETag canonFeatures[] = {ccmpFeatureTag, emptyTag};
       
   118 
       
   119 LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags)
       
   120   : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode),
       
   121     fTypoFlags(typoFlags), fGidOfRA(0)
       
   122 {
       
   123     fGlyphStorage = new LEGlyphStorage();
       
   124 }
       
   125 
       
   126 le_bool LayoutEngine::isBogus()
       
   127 {
       
   128     return fGlyphStorage? FALSE : TRUE;
       
   129 }
       
   130 
       
   131 le_int32 LayoutEngine::getGlyphCount() const
       
   132 {
       
   133     return fGlyphStorage->getGlyphCount();
       
   134 }
       
   135 
       
   136 void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
       
   137 {
       
   138     fGlyphStorage->getCharIndices(charIndices, indexBase, success);
       
   139 }
       
   140 
       
   141 void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
       
   142 {
       
   143     fGlyphStorage->getCharIndices(charIndices, success);
       
   144 }
       
   145 
       
   146 // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
       
   147 void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
       
   148 {
       
   149     fGlyphStorage->getGlyphs(glyphs, extraBits, success);
       
   150 }
       
   151 
       
   152 void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
       
   153 {
       
   154     fGlyphStorage->getGlyphs(glyphs, success);
       
   155 }
       
   156 
       
   157 
       
   158 void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const
       
   159 {
       
   160     fGlyphStorage->getGlyphPositions(positions, success);
       
   161 }
       
   162 
       
   163 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
       
   164 {
       
   165     fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success);
       
   166 }
       
   167 
       
   168 le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
       
   169                 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
       
   170 {
       
   171     if (LE_FAILURE(success)) {
       
   172         return 0;
       
   173     }
       
   174 
       
   175     if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
       
   176         success = LE_ILLEGAL_ARGUMENT_ERROR;
       
   177         return 0;
       
   178     }
       
   179 
       
   180     const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
       
   181     LETag scriptTag  = OpenTypeLayoutEngine::getScriptTag(fScriptCode);
       
   182     LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode);
       
   183     le_int32 i, dir = 1, out = 0, outCharCount = count;
       
   184 
       
   185     if (canonGSUBTable->coversScript(scriptTag)) {
       
   186         CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance);
       
   187         if (!substitutionFilter) {
       
   188             success = LE_MEMORY_ALLOCATION_ERROR;
       
   189             return 0;
       
   190         }
       
   191 
       
   192 		const LEUnicode *inChars = &chars[offset];
       
   193 		LEUnicode *reordered = NULL;
       
   194 
       
   195 		// This is the cheapest way to get mark reordering only for Hebrew.
       
   196 		// We could just do the mark reordering for all scripts, but most
       
   197 		// of them probably don't need it...
       
   198 		if (fScriptCode == hebrScriptCode) {
       
   199 			reordered = LE_NEW_ARRAY(LEUnicode, count);
       
   200 
       
   201 			if (reordered == NULL) {
       
   202 				success = LE_MEMORY_ALLOCATION_ERROR;
       
   203 				delete substitutionFilter;
       
   204 				return 0;
       
   205 			}
       
   206 
       
   207 			CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, glyphStorage);
       
   208 			inChars = reordered;
       
   209 		}
       
   210 
       
   211         glyphStorage.allocateGlyphArray(count, rightToLeft, success);
       
   212         glyphStorage.allocateAuxData(success);
       
   213 
       
   214         if (LE_FAILURE(success)) {
       
   215             delete substitutionFilter;
       
   216             return 0;
       
   217         }
       
   218 
       
   219         if (rightToLeft) {
       
   220             out = count - 1;
       
   221             dir = -1;
       
   222         }
       
   223 
       
   224         for (i = 0; i < count; i += 1, out += dir) {
       
   225             glyphStorage[out] = (LEGlyphID) inChars[i];
       
   226             glyphStorage.setAuxData(out, (void *) canonFeatures, success);
       
   227         }
       
   228 
       
   229 		if (reordered != NULL) {
       
   230 			LE_DELETE_ARRAY(reordered);
       
   231 		}
       
   232 
       
   233         outCharCount = canonGSUBTable->process(glyphStorage, rightToLeft,
       
   234             scriptTag, langSysTag, NULL, success, substitutionFilter, NULL);
       
   235 
       
   236         if (LE_FAILURE(success)) {
       
   237             delete substitutionFilter;
       
   238             return 0;
       
   239         }
       
   240 
       
   241         out = (rightToLeft? count - 1 : 0);
       
   242 
       
   243         outChars = LE_NEW_ARRAY(LEUnicode, outCharCount);
       
   244         if (!outChars) {
       
   245             delete substitutionFilter;
       
   246             success = LE_MEMORY_ALLOCATION_ERROR;
       
   247             return 0;
       
   248         }
       
   249         for (i = 0; i < outCharCount; i += 1, out += dir) {
       
   250             outChars[out] = (LEUnicode) LE_GET_GLYPH(glyphStorage[i]);
       
   251         }
       
   252 
       
   253         delete substitutionFilter;
       
   254     }
       
   255 
       
   256     return outCharCount;
       
   257 }
       
   258 
       
   259 le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
       
   260                                             LEGlyphStorage &glyphStorage, LEErrorCode &success)
       
   261 {
       
   262     if (LE_FAILURE(success)) {
       
   263         return 0;
       
   264     }
       
   265 
       
   266     if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
       
   267         success = LE_ILLEGAL_ARGUMENT_ERROR;
       
   268         return 0;
       
   269     }
       
   270 
       
   271     LEUnicode *outChars = NULL;
       
   272     le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success);
       
   273 
       
   274     if (outChars != NULL) {
       
   275         mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success);
       
   276         LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
       
   277     } else {
       
   278         mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
       
   279     }
       
   280 
       
   281     return glyphStorage.getGlyphCount();
       
   282 }
       
   283 
       
   284 // Input: glyphs
       
   285 // Output: positions
       
   286 void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success)
       
   287 {
       
   288     if (LE_FAILURE(success)) {
       
   289         return;
       
   290     }
       
   291 
       
   292     glyphStorage.allocatePositions(success);
       
   293 
       
   294     if (LE_FAILURE(success)) {
       
   295         return;
       
   296     }
       
   297 
       
   298     le_int32 i, glyphCount = glyphStorage.getGlyphCount();
       
   299 
       
   300     for (i = 0; i < glyphCount; i += 1) {
       
   301         LEPoint advance;
       
   302 
       
   303         glyphStorage.setPosition(i, x, y, success);
       
   304 
       
   305         fFontInstance->getGlyphAdvance(glyphStorage[i], advance);
       
   306         x += advance.fX;
       
   307         y += advance.fY;
       
   308     }
       
   309 
       
   310     glyphStorage.setPosition(glyphCount, x, y, success);
       
   311 }
       
   312 
       
   313 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool /*reverse*/,
       
   314                                         LEGlyphStorage &glyphStorage, LEErrorCode &success)
       
   315 {
       
   316     if (LE_FAILURE(success)) {
       
   317         return;
       
   318     }
       
   319 
       
   320     if (chars == NULL || offset < 0 || count < 0) {
       
   321         success = LE_ILLEGAL_ARGUMENT_ERROR;
       
   322         return;
       
   323     }
       
   324 
       
   325     if (fTypoFlags & 0x1) { /* kerning enabled */
       
   326       static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG;
       
   327 
       
   328       KernTable kt(fFontInstance, getFontTable(kernTableTag));
       
   329       kt.process(glyphStorage);
       
   330     }
       
   331 
       
   332     // default is no adjustments
       
   333     return;
       
   334 }
       
   335 
       
   336 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
       
   337 {
       
   338     float xAdjust = 0;
       
   339     le_int32 p, glyphCount = glyphStorage.getGlyphCount();
       
   340 
       
   341     if (LE_FAILURE(success)) {
       
   342         return;
       
   343     }
       
   344 
       
   345     if (markFilter == NULL) {
       
   346         success = LE_ILLEGAL_ARGUMENT_ERROR;
       
   347         return;
       
   348     }
       
   349 
       
   350     float ignore, prev;
       
   351 
       
   352     glyphStorage.getGlyphPosition(0, prev, ignore, success);
       
   353 
       
   354     for (p = 0; p < glyphCount; p += 1) {
       
   355         float next, xAdvance;
       
   356         
       
   357         glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
       
   358 
       
   359         xAdvance = next - prev;
       
   360         glyphStorage.adjustPosition(p, xAdjust, 0, success);
       
   361 
       
   362         if (markFilter->accept(glyphStorage[p])) {
       
   363             xAdjust -= xAdvance;
       
   364         }
       
   365 
       
   366         prev = next;
       
   367     }
       
   368 
       
   369     glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
       
   370 }
       
   371 
       
   372 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
       
   373 {
       
   374     float xAdjust = 0;
       
   375     le_int32 c = 0, direction = 1, p;
       
   376     le_int32 glyphCount = glyphStorage.getGlyphCount();
       
   377 
       
   378     if (LE_FAILURE(success)) {
       
   379         return;
       
   380     }
       
   381 
       
   382     if (markFilter == NULL) {
       
   383         success = LE_ILLEGAL_ARGUMENT_ERROR;
       
   384         return;
       
   385     }
       
   386 
       
   387     if (reverse) {
       
   388         c = glyphCount - 1;
       
   389         direction = -1;
       
   390     }
       
   391 
       
   392     float ignore, prev;
       
   393 
       
   394     glyphStorage.getGlyphPosition(0, prev, ignore, success);
       
   395 
       
   396     for (p = 0; p < charCount; p += 1, c += direction) {
       
   397         float next, xAdvance;
       
   398         
       
   399         glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
       
   400 
       
   401         xAdvance = next - prev;
       
   402         glyphStorage.adjustPosition(p, xAdjust, 0, success);
       
   403 
       
   404         if (markFilter->accept(chars[c])) {
       
   405             xAdjust -= xAdvance;
       
   406         }
       
   407 
       
   408         prev = next;
       
   409     }
       
   410 
       
   411     glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
       
   412 }
       
   413 
       
   414 const void *LayoutEngine::getFontTable(LETag tableTag) const
       
   415 {
       
   416     return fFontInstance->getFontTable(tableTag);
       
   417 }
       
   418 
       
   419 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
       
   420                                     LEGlyphStorage &glyphStorage, LEErrorCode &success)
       
   421 {
       
   422     if (LE_FAILURE(success)) {
       
   423         return;
       
   424     }
       
   425 
       
   426     glyphStorage.allocateGlyphArray(count, reverse, success);
       
   427 
       
   428     DefaultCharMapper charMapper(TRUE, mirror);
       
   429 
       
   430     fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, glyphStorage);
       
   431 }
       
   432 
       
   433 // Input: characters, font?
       
   434 // Output: glyphs, positions, char indices
       
   435 // Returns: number of glyphs
       
   436 le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
       
   437                               float x, float y, LEErrorCode &success)
       
   438 {
       
   439     if (LE_FAILURE(success)) {
       
   440         return 0;
       
   441     }
       
   442 
       
   443     if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
       
   444         success = LE_ILLEGAL_ARGUMENT_ERROR;
       
   445         return 0;
       
   446     }
       
   447 
       
   448     // 1922 mlyl: get the glyph ID of RAKAR -->
       
   449     const LEUnicode RAKAR[] = {0xFFFF, 0xD15, 0xD4D, 0xD30, 0xFFFF};
       
   450     if (fGidOfRA == 0 && mlymScriptCode == fScriptCode) {
       
   451     	fGidOfRA = -1;  // 0xFFFFFFFF
       
   452     	TInt noOfGlyphs = layoutChars(
       
   453     			RAKAR, 		// chars - the input character context
       
   454     			1,			// the offset of the first character to process	
       
   455     			3,			// count - the number of characters to process	// offset
       
   456     			5, 			// max - the number of characters in the input context	// size of text
       
   457     			FALSE, 		// rightToLeft - TRUE if the characters are in a right to left directional run
       
   458     			0, 			// start X
       
   459     			0, 			// start Y
       
   460     			success);	// result code
       
   461     	
       
   462     	if (!LE_FAILURE(success)) {
       
   463     		fGidOfRA = (*fGlyphStorage)[1];
       
   464     		(*fGlyphStorage).reset();
       
   465     	}
       
   466     }
       
   467     // <-- 1922 mlyl
       
   468     
       
   469     le_int32 glyphCount;
       
   470     
       
   471     glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success);
       
   472     
       
   473     // 1922 mlyl: put RAKAR left of the preceding glyph -->
       
   474     if (fGidOfRA != 0 && fGidOfRA != -1 && mlymScriptCode == fScriptCode) {
       
   475     	fGlyphStorage->forMlylRakar(fGidOfRA);
       
   476     }
       
   477     // <-- 1922 mlyl
       
   478     
       
   479     positionGlyphs(*fGlyphStorage, x, y, success);
       
   480     adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success);
       
   481 
       
   482     return glyphCount;
       
   483 }
       
   484 
       
   485 void LayoutEngine::reset()
       
   486 {
       
   487     fGlyphStorage->reset();
       
   488 }
       
   489     
       
   490 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success)
       
   491 {
       
   492   // 3 -> kerning and ligatures
       
   493   return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, 3, success);
       
   494 }
       
   495     
       
   496 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
       
   497 {
       
   498     static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
       
   499     static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
       
   500 
       
   501     if (LE_FAILURE(success)) {
       
   502         return NULL;
       
   503     }
       
   504 
       
   505     const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag);
       
   506     LayoutEngine *result = NULL;
       
   507     LETag scriptTag   = 0x00000000;
       
   508     LETag languageTag = 0x00000000;
       
   509 
       
   510     if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) {
       
   511         switch (scriptCode) {
       
   512         case bengScriptCode:
       
   513         case devaScriptCode:
       
   514         case gujrScriptCode:
       
   515         case kndaScriptCode:
       
   516         case mlymScriptCode:
       
   517         case oryaScriptCode:
       
   518         case guruScriptCode:
       
   519         case tamlScriptCode:
       
   520         case teluScriptCode:
       
   521             result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
       
   522             break;
       
   523 
       
   524         case arabScriptCode:
       
   525             result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
       
   526             break;
       
   527 
       
   528         case haniScriptCode:
       
   529             languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
       
   530 
       
   531             switch (languageCode) {
       
   532             case korLanguageCode:
       
   533             case janLanguageCode:
       
   534             case zhtLanguageCode:
       
   535             case zhsLanguageCode:
       
   536                 if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) {
       
   537                     result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
       
   538                     break;
       
   539                 }
       
   540 
       
   541                 // note: falling through to default case.
       
   542             default:
       
   543                 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
       
   544                 break;
       
   545             }
       
   546 
       
   547             break;
       
   548 
       
   549         case khmrScriptCode:
       
   550             result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
       
   551             break;
       
   552 
       
   553         default:
       
   554             result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
       
   555             break;
       
   556         }
       
   557     } else {
       
   558         const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag);
       
   559 
       
   560         if (morphTable != NULL) {
       
   561             result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable);
       
   562         } else {
       
   563             switch (scriptCode) {
       
   564             case bengScriptCode:
       
   565             case devaScriptCode:
       
   566             case gujrScriptCode:
       
   567             case kndaScriptCode:
       
   568             case mlymScriptCode:
       
   569             case oryaScriptCode:
       
   570             case guruScriptCode:
       
   571             case tamlScriptCode:
       
   572             case teluScriptCode:
       
   573             {
       
   574                 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
       
   575                 break;
       
   576             }
       
   577 
       
   578             case arabScriptCode:
       
   579             //case hebrScriptCode:
       
   580                 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
       
   581                 break;
       
   582 
       
   583             //case hebrScriptCode:
       
   584             //    return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
       
   585 
       
   586             case thaiScriptCode:
       
   587                 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
       
   588                 break;
       
   589 
       
   590             default:
       
   591                 result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
       
   592                 break;
       
   593             }
       
   594         }
       
   595     }
       
   596 
       
   597     if (result && result->isBogus()) {
       
   598         delete result;
       
   599         result = NULL;
       
   600     }
       
   601     if (result == NULL) {
       
   602         success = LE_MEMORY_ALLOCATION_ERROR;
       
   603     }
       
   604 
       
   605     return result;
       
   606 }
       
   607 
       
   608 LayoutEngine::~LayoutEngine() {
       
   609     delete fGlyphStorage;
       
   610 }
       
   611 
       
   612 U_NAMESPACE_END