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
64U_NAMESPACE_BEGIN
65
66/* Leave this copyright notice here! It needs to go somewhere in this library. */
67static const char copyright[] = U_COPYRIGHT_STRING;
68
69/* TODO: remove these? */
70const le_int32 LayoutEngine::kTypoFlagKern = LE_Kerning_FEATURE_FLAG;
71const le_int32 LayoutEngine::kTypoFlagLiga = LE_Ligatures_FEATURE_FLAG;
72
73const 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
80const le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars);
81
82const 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
89const le_int32 DefaultCharMapper::controlCharsZWJCount = LE_ARRAY_SIZE(controlCharsZWJ);
90
91LEUnicode32 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...
131LEGlyphFilter::~LEGlyphFilter()
132{
133    // nothing to do
134}
135
136CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance)
137  : fFontInstance(fontInstance)
138{
139    // nothing to do
140}
141
142CharSubstitutionFilter::~CharSubstitutionFilter()
143{
144    // nothing to do
145}
146
147class CanonMarkFilter : public UMemory, public LEGlyphFilter
148{
149private:
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
155public:
156    CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success);
157    virtual ~CanonMarkFilter();
158
159    virtual le_bool accept(LEGlyphID glyph, LEErrorCode &success) const;
160};
161
162CanonMarkFilter::CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success)
163  : classDefTable(gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success))
164{
165}
166
167CanonMarkFilter::~CanonMarkFilter()
168{
169    // nothing to do?
170}
171
172le_bool CanonMarkFilter::accept(LEGlyphID glyph, LEErrorCode &success) const
173{
174  le_int32 glyphClass = classDefTable->getGlyphClass(classDefTable, glyph, success);
175  if(LE_FAILURE(success)) return false;
176  return glyphClass != 0;
177}
178
179UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine)
180
181#define ccmpFeatureTag  LE_CCMP_FEATURE_TAG
182
183#define ccmpFeatureMask 0x80000000UL
184
185#define canonFeatures (ccmpFeatureMask)
186
187static const FeatureMap canonFeatureMap[] =
188{
189    {ccmpFeatureTag, ccmpFeatureMask}
190};
191
192static const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap);
193
194LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance,
195                           le_int32 scriptCode,
196                           le_int32 languageCode,
197                           le_int32 typoFlags,
198                           LEErrorCode &success)
199  : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode),
200    fTypoFlags(typoFlags), fFilterZeroWidth(TRUE)
201{
202    if (LE_FAILURE(success)) {
203        return;
204    }
205
206    fGlyphStorage = new LEGlyphStorage();
207    if (fGlyphStorage == NULL) {
208        success = LE_MEMORY_ALLOCATION_ERROR;
209    }
210}
211
212le_int32 LayoutEngine::getGlyphCount() const
213{
214    return fGlyphStorage->getGlyphCount();
215}
216
217void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
218{
219    fGlyphStorage->getCharIndices(charIndices, indexBase, success);
220}
221
222void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
223{
224    fGlyphStorage->getCharIndices(charIndices, success);
225}
226
227// Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
228void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
229{
230    fGlyphStorage->getGlyphs(glyphs, extraBits, success);
231}
232
233void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
234{
235    fGlyphStorage->getGlyphs(glyphs, success);
236}
237
238
239void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const
240{
241    fGlyphStorage->getGlyphPositions(positions, success);
242}
243
244void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
245{
246    fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success);
247}
248
249le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
250                LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
251{
252    if (LE_FAILURE(success)) {
253        return 0;
254    }
255
256    if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
257        success = LE_ILLEGAL_ARGUMENT_ERROR;
258        return 0;
259    }
260
261    if ((fTypoFlags & LE_NoCanon_FEATURE_FLAG) == 0) { // no canonical processing
262      return count;
263    }
264
265    LEReferenceTo<GlyphSubstitutionTableHeader> canonGSUBTable(LETableReference::kStaticData,
266                                                               (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable,
267                                                               CanonShaping::glyphSubstitutionTableLen);
268    LETag scriptTag  = OpenTypeLayoutEngine::getScriptTag(fScriptCode);
269    LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode);
270    le_int32 i, dir = 1, out = 0, outCharCount = count;
271
272    if (canonGSUBTable->coversScript(canonGSUBTable,scriptTag, success) || LE_SUCCESS(success)) {
273        CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance);
274        if (substitutionFilter == NULL) {
275            success = LE_MEMORY_ALLOCATION_ERROR;
276            return 0;
277        }
278
279        const LEUnicode *inChars = &chars[offset];
280        LEUnicode *reordered = NULL;
281        LEGlyphStorage fakeGlyphStorage;
282
283        fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success);
284
285        if (LE_FAILURE(success)) {
286            delete substitutionFilter;
287            return 0;
288        }
289
290        // This is the cheapest way to get mark reordering only for Hebrew.
291        // We could just do the mark reordering for all scripts, but most
292        // of them probably don't need it...
293        if (fScriptCode == hebrScriptCode) {
294          reordered = LE_NEW_ARRAY(LEUnicode, count);
295
296          if (reordered == NULL) {
297            delete substitutionFilter;
298            success = LE_MEMORY_ALLOCATION_ERROR;
299            return 0;
300          }
301
302          CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage);
303          inChars = reordered;
304        }
305
306        fakeGlyphStorage.allocateAuxData(success);
307
308        if (LE_FAILURE(success)) {
309            delete substitutionFilter;
310            return 0;
311        }
312
313        if (rightToLeft) {
314            out = count - 1;
315            dir = -1;
316        }
317
318        for (i = 0; i < count; i += 1, out += dir) {
319            fakeGlyphStorage[out] = (LEGlyphID) inChars[i];
320            fakeGlyphStorage.setAuxData(out, canonFeatures, success);
321        }
322
323        if (reordered != NULL) {
324          LE_DELETE_ARRAY(reordered);
325        }
326
327        const LEReferenceTo<GlyphDefinitionTableHeader>  noGDEF; // empty gdef header
328        outCharCount = canonGSUBTable->process(canonGSUBTable, fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, noGDEF, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success);
329
330        if (LE_FAILURE(success)) {
331            delete substitutionFilter;
332            return 0;
333        }
334
335        out = (rightToLeft? outCharCount - 1 : 0);
336
337        /*
338         * The char indices array in fakeGlyphStorage has the correct mapping
339         * back to the original input characters. Save it in glyphStorage. The
340         * subsequent call to glyphStoratge.allocateGlyphArray will keep this
341         * array rather than allocating and initializing a new one.
342         */
343        glyphStorage.adoptCharIndicesArray(fakeGlyphStorage);
344
345        outChars = LE_NEW_ARRAY(LEUnicode, outCharCount);
346
347        if (outChars == NULL) {
348            delete substitutionFilter;
349            success = LE_MEMORY_ALLOCATION_ERROR;
350            return 0;
351        }
352
353        for (i = 0; i < outCharCount; i += 1, out += dir) {
354            outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]);
355        }
356
357        delete substitutionFilter;
358    }
359
360    return outCharCount;
361}
362
363le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
364                                            LEGlyphStorage &glyphStorage, LEErrorCode &success)
365{
366    if (LE_FAILURE(success)) {
367        return 0;
368    }
369
370    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
371        success = LE_ILLEGAL_ARGUMENT_ERROR;
372        return 0;
373    }
374
375    LEUnicode *outChars = NULL;
376    le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success);
377
378    if (outChars != NULL) {
379        mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success);
380        LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
381    } else {
382        mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
383    }
384
385    return glyphStorage.getGlyphCount();
386}
387
388// Input: glyphs
389// Output: positions
390void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success)
391{
392    if (LE_FAILURE(success)) {
393        return;
394    }
395
396    glyphStorage.allocatePositions(success);
397
398    if (LE_FAILURE(success)) {
399        return;
400    }
401
402    le_int32 i, glyphCount = glyphStorage.getGlyphCount();
403
404    for (i = 0; i < glyphCount; i += 1) {
405        LEPoint advance;
406
407        glyphStorage.setPosition(i, x, y, success);
408        _LETRACE("g#%-4d (%.2f, %.2f)", i, x, y);
409
410        fFontInstance->getGlyphAdvance(glyphStorage[i], advance);
411        x += advance.fX;
412        y += advance.fY;
413
414
415    }
416
417    glyphStorage.setPosition(glyphCount, x, y, success);
418}
419
420void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
421                                        LEGlyphStorage &glyphStorage, LEErrorCode &success)
422{
423    if (LE_FAILURE(success)) {
424        return;
425    }
426
427    if (chars == NULL || offset < 0 || count < 0) {
428        success = LE_ILLEGAL_ARGUMENT_ERROR;
429        return;
430    }
431
432    LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(LETableReference::kStaticData, (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable,
433                                                        CanonShaping::glyphDefinitionTableLen);
434    CanonMarkFilter filter(gdefTable, success);
435
436    adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
437
438    if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */
439      LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success);
440      KernTable kt(kernTable, success);
441      kt.process(glyphStorage, success);
442    }
443
444    // default is no adjustments
445    return;
446}
447
448void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
449{
450    float xAdjust = 0;
451    le_int32 p, glyphCount = glyphStorage.getGlyphCount();
452
453    if (LE_FAILURE(success)) {
454        return;
455    }
456
457    if (markFilter == NULL) {
458        success = LE_ILLEGAL_ARGUMENT_ERROR;
459        return;
460    }
461
462    float ignore, prev;
463
464    glyphStorage.getGlyphPosition(0, prev, ignore, success);
465
466    for (p = 0; p < glyphCount; p += 1) {
467        float next, xAdvance;
468
469        glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
470
471        xAdvance = next - prev;
472        _LETRACE("p#%d (%.2f,%.2f)", p, xAdvance, 0);
473        glyphStorage.adjustPosition(p, xAdjust, 0, success);
474
475        if (markFilter->accept(glyphStorage[p], success)) {
476            xAdjust -= xAdvance;
477        }
478
479        prev = next;
480    }
481
482    glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
483}
484
485void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
486{
487    float xAdjust = 0;
488    le_int32 c = 0, direction = 1, p;
489    le_int32 glyphCount = glyphStorage.getGlyphCount();
490
491    if (LE_FAILURE(success)) {
492        return;
493    }
494
495    if (markFilter == NULL) {
496        success = LE_ILLEGAL_ARGUMENT_ERROR;
497        return;
498    }
499
500    if (reverse) {
501        c = glyphCount - 1;
502        direction = -1;
503    }
504
505    float ignore, prev;
506
507    glyphStorage.getGlyphPosition(0, prev, ignore, success);
508
509    for (p = 0; p < charCount; p += 1, c += direction) {
510        float next, xAdvance;
511
512        glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
513
514        xAdvance = next - prev;
515
516        _LETRACE("p#%d (%.2f,%.2f)", p, xAdvance, 0);
517
518
519        glyphStorage.adjustPosition(p, xAdjust, 0, success);
520
521        if (markFilter->accept(chars[c], success)) {
522            xAdjust -= xAdvance;
523        }
524
525        prev = next;
526    }
527
528    glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
529}
530
531const void *LayoutEngine::getFontTable(LETag tableTag, size_t &length) const
532{
533  return fFontInstance->getFontTable(tableTag, length);
534}
535
536void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
537                                    LEGlyphStorage &glyphStorage, LEErrorCode &success)
538{
539    if (LE_FAILURE(success)) {
540        return;
541    }
542
543    glyphStorage.allocateGlyphArray(count, reverse, success);
544
545    DefaultCharMapper charMapper(TRUE, mirror);
546
547    fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, fFilterZeroWidth, glyphStorage);
548}
549
550// Input: characters, font?
551// Output: glyphs, positions, char indices
552// Returns: number of glyphs
553le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
554                              float x, float y, LEErrorCode &success)
555{
556    if (LE_FAILURE(success)) {
557        return 0;
558    }
559
560    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
561        success = LE_ILLEGAL_ARGUMENT_ERROR;
562        return 0;
563    }
564
565    le_int32 glyphCount;
566
567    if (fGlyphStorage->getGlyphCount() > 0) {
568        fGlyphStorage->reset();
569    }
570
571    glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success);
572    positionGlyphs(*fGlyphStorage, x, y, success);
573    adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success);
574
575    return glyphCount;
576}
577
578void LayoutEngine::reset()
579{
580  if(fGlyphStorage!=NULL) {
581    fGlyphStorage->reset();
582  }
583}
584
585LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success)
586{
587  //kerning and ligatures - by default
588  return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, LE_DEFAULT_FEATURE_FLAG, success);
589}
590
591LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
592{
593    static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
594    static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
595    static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG;
596
597    if (LE_FAILURE(success)) {
598        return NULL;
599    }
600
601    LEReferenceTo<GlyphSubstitutionTableHeader> gsubTable(fontInstance,gsubTableTag,success);
602    LayoutEngine *result = NULL;
603    LETag scriptTag   = 0x00000000;
604    LETag languageTag = 0x00000000;
605    LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode);
606
607    // Right now, only invoke V2 processing for Devanagari.  TODO: Allow more V2 scripts as they are
608    // properly tested.
609
610    if ( v2ScriptTag == dev2ScriptTag && gsubTable.isValid() && gsubTable->coversScript(gsubTable, v2ScriptTag, success )) {
611      result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success);
612    }
613    else if (gsubTable.isValid() && gsubTable->coversScript(gsubTable, scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode), success)) {
614        switch (scriptCode) {
615        case bengScriptCode:
616        case devaScriptCode:
617        case gujrScriptCode:
618        case kndaScriptCode:
619        case mlymScriptCode:
620        case oryaScriptCode:
621        case guruScriptCode:
622        case tamlScriptCode:
623        case teluScriptCode:
624        case sinhScriptCode:
625            result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success);
626            break;
627
628        case arabScriptCode:
629            result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
630            break;
631
632        case hebrScriptCode:
633            // Disable hebrew ligatures since they have only archaic uses, see ticket #8318
634            result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success);
635            break;
636
637        case hangScriptCode:
638            result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
639            break;
640
641        case haniScriptCode:
642            languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
643
644            switch (languageCode) {
645            case korLanguageCode:
646            case janLanguageCode:
647            case zhtLanguageCode:
648            case zhsLanguageCode:
649              if (gsubTable->coversScriptAndLanguage(gsubTable, scriptTag, languageTag, success, TRUE)) {
650                    result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
651                    break;
652              }
653
654                // note: falling through to default case.
655            default:
656                result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
657                break;
658            }
659
660            break;
661
662        case tibtScriptCode:
663            result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
664            break;
665
666        case khmrScriptCode:
667            result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
668            break;
669
670        default:
671            result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
672            break;
673        }
674    } else {
675        LEReferenceTo<MorphTableHeader2> morxTable(fontInstance, morxTableTag, success);
676        if (LE_SUCCESS(success) &&
677            morxTable.isValid() &&
678            SWAPL(morxTable->version)==0x00020000) {
679            result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success);
680        } else {
681          LEReferenceTo<MorphTableHeader> mortTable(fontInstance, mortTableTag, success);
682          if (LE_SUCCESS(success) && mortTable.isValid() && SWAPL(mortTable->version)==0x00010000) { // mort
683            result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success);
684            } else {
685                switch (scriptCode) {
686                    case bengScriptCode:
687                    case devaScriptCode:
688                    case gujrScriptCode:
689                    case kndaScriptCode:
690                    case mlymScriptCode:
691                    case oryaScriptCode:
692                    case guruScriptCode:
693                    case tamlScriptCode:
694                    case teluScriptCode:
695                    case sinhScriptCode:
696                    {
697                        result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
698                        break;
699                    }
700
701                case arabScriptCode:
702                  result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
703                  break;
704
705                  //case hebrScriptCode:
706                  //    return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
707
708                case thaiScriptCode:
709                  result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
710                  break;
711
712                case hangScriptCode:
713                  result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
714                  break;
715
716                    default:
717                        result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
718                        break;
719                }
720            }
721        }
722    }
723
724    if (result && LE_FAILURE(success)) {
725      delete result;
726      result = NULL;
727    }
728
729    if (result == NULL) {
730        success = LE_MEMORY_ALLOCATION_ERROR;
731    }
732
733    return result;
734}
735
736LayoutEngine::~LayoutEngine() {
737    delete fGlyphStorage;
738}
739
740U_NAMESPACE_END
741