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