• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) Copyright IBM Corp. 1998-2011 - All Rights Reserved
3  */
4 
5 #include "LETypes.h"
6 #include "LEScripts.h"
7 #include "LELanguages.h"
8 
9 #include "LayoutEngine.h"
10 #include "ArabicLayoutEngine.h"
11 #include "CanonShaping.h"
12 #include "HanLayoutEngine.h"
13 #include "HangulLayoutEngine.h"
14 #include "IndicLayoutEngine.h"
15 #include "KhmerLayoutEngine.h"
16 #include "ThaiLayoutEngine.h"
17 #include "TibetanLayoutEngine.h"
18 #include "GXLayoutEngine.h"
19 #include "ScriptAndLanguageTags.h"
20 #include "CharSubstitutionFilter.h"
21 
22 #include "LEGlyphStorage.h"
23 
24 #include "OpenTypeUtilities.h"
25 #include "GlyphSubstitutionTables.h"
26 #include "GlyphDefinitionTables.h"
27 #include "MorphTables.h"
28 
29 #include "DefaultCharMapper.h"
30 
31 #include "KernTable.h"
32 
33 U_NAMESPACE_BEGIN
34 
35 /* Leave this copyright notice here! It needs to go somewhere in this library. */
36 static const char copyright[] = U_COPYRIGHT_STRING;
37 
38 const le_int32 LayoutEngine::kTypoFlagKern = 0x1;
39 const le_int32 LayoutEngine::kTypoFlagLiga = 0x2;
40 
41 const LEUnicode32 DefaultCharMapper::controlChars[] = {
42     0x0009, 0x000A, 0x000D,
43     /*0x200C, 0x200D,*/ 0x200E, 0x200F,
44     0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
45     0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
46 };
47 
48 const le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars);
49 
mapChar(LEUnicode32 ch) const50 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...
~LEGlyphFilter()74 LEGlyphFilter::~LEGlyphFilter()
75 {
76     // nothing to do
77 }
78 
CharSubstitutionFilter(const LEFontInstance * fontInstance)79 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance)
80   : fFontInstance(fontInstance)
81 {
82     // nothing to do
83 }
84 
~CharSubstitutionFilter()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 
CanonMarkFilter(const GlyphDefinitionTableHeader * gdefTable)105 CanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable)
106 {
107     classDefTable = gdefTable->getMarkAttachClassDefinitionTable();
108 }
109 
~CanonMarkFilter()110 CanonMarkFilter::~CanonMarkFilter()
111 {
112     // nothing to do?
113 }
114 
accept(LEGlyphID glyph) const115 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 
LayoutEngine(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags,LEErrorCode & success)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 
getGlyphCount() const155 le_int32 LayoutEngine::getGlyphCount() const
156 {
157     return fGlyphStorage->getGlyphCount();
158 }
159 
getCharIndices(le_int32 charIndices[],le_int32 indexBase,LEErrorCode & success) const160 void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
161 {
162     fGlyphStorage->getCharIndices(charIndices, indexBase, success);
163 }
164 
getCharIndices(le_int32 charIndices[],LEErrorCode & success) const165 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
getGlyphs(le_uint32 glyphs[],le_uint32 extraBits,LEErrorCode & success) const171 void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
172 {
173     fGlyphStorage->getGlyphs(glyphs, extraBits, success);
174 }
175 
getGlyphs(LEGlyphID glyphs[],LEErrorCode & success) const176 void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
177 {
178     fGlyphStorage->getGlyphs(glyphs, success);
179 }
180 
181 
getGlyphPositions(float positions[],LEErrorCode & success) const182 void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const
183 {
184     fGlyphStorage->getGlyphPositions(positions, success);
185 }
186 
getGlyphPosition(le_int32 glyphIndex,float & x,float & y,LEErrorCode & success) const187 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
188 {
189     fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success);
190 }
191 
characterProcessing(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEUnicode * & outChars,LEGlyphStorage & glyphStorage,LEErrorCode & success)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 
computeGlyphs(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEGlyphStorage & glyphStorage,LEErrorCode & success)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
positionGlyphs(LEGlyphStorage & glyphStorage,float x,float y,LEErrorCode & success)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 
adjustGlyphPositions(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,LEGlyphStorage & glyphStorage,LEErrorCode & success)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 
adjustMarkGlyphs(LEGlyphStorage & glyphStorage,LEGlyphFilter * markFilter,LEErrorCode & success)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 
adjustMarkGlyphs(const LEUnicode chars[],le_int32 charCount,le_bool reverse,LEGlyphStorage & glyphStorage,LEGlyphFilter * markFilter,LEErrorCode & success)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 
getFontTable(LETag tableTag) const459 const void *LayoutEngine::getFontTable(LETag tableTag) const
460 {
461     return fFontInstance->getFontTable(tableTag);
462 }
463 
mapCharsToGlyphs(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,le_bool mirror,LEGlyphStorage & glyphStorage,LEErrorCode & success)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
layoutChars(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,float x,float y,LEErrorCode & success)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 
reset()506 void LayoutEngine::reset()
507 {
508     fGlyphStorage->reset();
509 }
510 
layoutEngineFactory(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,LEErrorCode & success)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 
layoutEngineFactory(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags,LEErrorCode & success)517 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
518 {
519     static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
520     static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
521 
522     if (LE_FAILURE(success)) {
523         return NULL;
524     }
525 
526     const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag);
527     LayoutEngine *result = NULL;
528     LETag scriptTag   = 0x00000000;
529     LETag languageTag = 0x00000000;
530 	LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode);
531 
532     // Right now, only invoke V2 processing for Devanagari.  TODO: Allow more V2 scripts as they are
533     // properly tested.
534 
535 	if ( v2ScriptTag == dev2ScriptTag && gsubTable != NULL && gsubTable->coversScript( v2ScriptTag )) {
536 		result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success);
537 	}
538     else if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) {
539         switch (scriptCode) {
540         case bengScriptCode:
541         case devaScriptCode:
542         case gujrScriptCode:
543         case kndaScriptCode:
544         case mlymScriptCode:
545         case oryaScriptCode:
546         case guruScriptCode:
547         case tamlScriptCode:
548         case teluScriptCode:
549         case sinhScriptCode:
550             result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success);
551             break;
552 
553         case arabScriptCode:
554             result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
555             break;
556 
557         case hebrScriptCode:
558             // Disable hebrew ligatures since they have only archaic uses, see ticket #8318
559             result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success);
560             break;
561 
562         case hangScriptCode:
563             result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
564             break;
565 
566         case haniScriptCode:
567             languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
568 
569             switch (languageCode) {
570             case korLanguageCode:
571             case janLanguageCode:
572             case zhtLanguageCode:
573             case zhsLanguageCode:
574                 if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) {
575                     result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
576                     break;
577                 }
578 
579                 // note: falling through to default case.
580             default:
581                 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
582                 break;
583             }
584 
585             break;
586 
587         case tibtScriptCode:
588             result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
589             break;
590 
591         case khmrScriptCode:
592             result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
593             break;
594 
595         default:
596             result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
597             break;
598         }
599     } else {
600         const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag);
601 
602         if (morphTable != NULL) {
603             result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable, success);
604         } else {
605             switch (scriptCode) {
606             case bengScriptCode:
607             case devaScriptCode:
608             case gujrScriptCode:
609             case kndaScriptCode:
610             case mlymScriptCode:
611             case oryaScriptCode:
612             case guruScriptCode:
613             case tamlScriptCode:
614             case teluScriptCode:
615             case sinhScriptCode:
616             {
617                 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
618                 break;
619             }
620 
621             case arabScriptCode:
622             //case hebrScriptCode:
623                 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
624                 break;
625 
626             //case hebrScriptCode:
627             //    return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
628 
629             case thaiScriptCode:
630                 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
631                 break;
632 
633             case hangScriptCode:
634                 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
635                 break;
636 
637             default:
638                 result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
639                 break;
640             }
641         }
642     }
643 
644     if (result && LE_FAILURE(success)) {
645 		delete result;
646 		result = NULL;
647 	}
648 
649     if (result == NULL) {
650         success = LE_MEMORY_ALLOCATION_ERROR;
651     }
652 
653     return result;
654 }
655 
~LayoutEngine()656 LayoutEngine::~LayoutEngine() {
657     delete fGlyphStorage;
658 }
659 
660 U_NAMESPACE_END
661