• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  *
4  * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
5  *
6  */
7 
8 #include "LETypes.h"
9 #include "LEScripts.h"
10 #include "LELanguages.h"
11 
12 #include "LayoutEngine.h"
13 #include "ArabicLayoutEngine.h"
14 #include "CanonShaping.h"
15 #include "HanLayoutEngine.h"
16 #include "HangulLayoutEngine.h"
17 #include "IndicLayoutEngine.h"
18 #include "KhmerLayoutEngine.h"
19 #include "ThaiLayoutEngine.h"
20 #include "TibetanLayoutEngine.h"
21 #include "GXLayoutEngine.h"
22 #include "ScriptAndLanguageTags.h"
23 #include "CharSubstitutionFilter.h"
24 
25 #include "LEGlyphStorage.h"
26 
27 #include "OpenTypeUtilities.h"
28 #include "GlyphSubstitutionTables.h"
29 #include "GlyphDefinitionTables.h"
30 #include "MorphTables.h"
31 
32 #include "DefaultCharMapper.h"
33 
34 #include "KernTable.h"
35 
36 U_NAMESPACE_BEGIN
37 
38 /* Leave this copyright notice here! It needs to go somewhere in this library. */
39 static const char copyright[] = U_COPYRIGHT_STRING;
40 
41 const LEUnicode32 DefaultCharMapper::controlChars[] = {
42     0x0009, 0x000A, 0x000D,
43     /*0x200C, 0x200D,*/ 0x200E, 0x200F,
44     0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
45     0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
46 };
47 
48 const le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars);
49 
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)137 LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags)
138   : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode),
139     fTypoFlags(typoFlags), fFilterZeroWidth(FALSE)
140 {
141     fGlyphStorage = new LEGlyphStorage();
142 }
143 
getGlyphCount() const144 le_int32 LayoutEngine::getGlyphCount() const
145 {
146     return fGlyphStorage->getGlyphCount();
147 }
148 
getCharIndices(le_int32 charIndices[],le_int32 indexBase,LEErrorCode & success) const149 void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
150 {
151     fGlyphStorage->getCharIndices(charIndices, indexBase, success);
152 }
153 
getCharIndices(le_int32 charIndices[],LEErrorCode & success) const154 void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
155 {
156     fGlyphStorage->getCharIndices(charIndices, success);
157 }
158 
159 // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
getGlyphs(le_uint32 glyphs[],le_uint32 extraBits,LEErrorCode & success) const160 void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
161 {
162     fGlyphStorage->getGlyphs(glyphs, extraBits, success);
163 }
164 
getGlyphs(LEGlyphID glyphs[],LEErrorCode & success) const165 void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
166 {
167     fGlyphStorage->getGlyphs(glyphs, success);
168 }
169 
170 
getGlyphPositions(float positions[],LEErrorCode & success) const171 void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const
172 {
173     fGlyphStorage->getGlyphPositions(positions, success);
174 }
175 
getGlyphPosition(le_int32 glyphIndex,float & x,float & y,LEErrorCode & success) const176 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
177 {
178     fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success);
179 }
180 
characterProcessing(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEUnicode * & outChars,LEGlyphStorage &,LEErrorCode & success)181 le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
182                 LEUnicode *&outChars, LEGlyphStorage &/*glyphStorage*/, LEErrorCode &success)
183 {
184     if (LE_FAILURE(success)) {
185         return 0;
186     }
187 
188     if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
189         success = LE_ILLEGAL_ARGUMENT_ERROR;
190         return 0;
191     }
192 
193     const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
194     LETag scriptTag  = OpenTypeLayoutEngine::getScriptTag(fScriptCode);
195     LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode);
196     le_int32 i, dir = 1, out = 0, outCharCount = count;
197 
198     if (canonGSUBTable->coversScript(scriptTag)) {
199         CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance);
200 		const LEUnicode *inChars = &chars[offset];
201 		LEUnicode *reordered = NULL;
202         LEGlyphStorage fakeGlyphStorage;
203 
204         fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success);
205 
206         if (LE_FAILURE(success)) {
207             return 0;
208         }
209 
210 		// This is the cheapest way to get mark reordering only for Hebrew.
211 		// We could just do the mark reordering for all scripts, but most
212 		// of them probably don't need it...
213 		if (fScriptCode == hebrScriptCode) {
214 			reordered = LE_NEW_ARRAY(LEUnicode, count);
215 
216 			if (reordered == NULL) {
217 				success = LE_MEMORY_ALLOCATION_ERROR;
218 				return 0;
219 			}
220 
221 			CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage);
222 			inChars = reordered;
223         }
224 
225         fakeGlyphStorage.allocateAuxData(success);
226 
227         if (LE_FAILURE(success)) {
228             return 0;
229         }
230 
231         if (rightToLeft) {
232             out = count - 1;
233             dir = -1;
234         }
235 
236         for (i = 0; i < count; i += 1, out += dir) {
237             fakeGlyphStorage[out] = (LEGlyphID) inChars[i];
238             fakeGlyphStorage.setAuxData(out, canonFeatures, success);
239         }
240 
241 		if (reordered != NULL) {
242 			LE_DELETE_ARRAY(reordered);
243 		}
244 
245         outCharCount = canonGSUBTable->process(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE);
246 
247         out = (rightToLeft? outCharCount - 1 : 0);
248 
249         outChars = LE_NEW_ARRAY(LEUnicode, outCharCount);
250         for (i = 0; i < outCharCount; i += 1, out += dir) {
251             outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]);
252         }
253 
254         delete substitutionFilter;
255     }
256 
257     return outCharCount;
258 }
259 
computeGlyphs(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEGlyphStorage & glyphStorage,LEErrorCode & success)260 le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
261                                             LEGlyphStorage &glyphStorage, LEErrorCode &success)
262 {
263     if (LE_FAILURE(success)) {
264         return 0;
265     }
266 
267     if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
268         success = LE_ILLEGAL_ARGUMENT_ERROR;
269         return 0;
270     }
271 
272     LEUnicode *outChars = NULL;
273     le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success);
274 
275     if (outChars != NULL) {
276         mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success);
277         LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
278     } else {
279         mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
280     }
281 
282     return glyphStorage.getGlyphCount();
283 }
284 
285 // Input: glyphs
286 // Output: positions
positionGlyphs(LEGlyphStorage & glyphStorage,float x,float y,LEErrorCode & success)287 void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success)
288 {
289     if (LE_FAILURE(success)) {
290         return;
291     }
292 
293     glyphStorage.allocatePositions(success);
294 
295     if (LE_FAILURE(success)) {
296         return;
297     }
298 
299     le_int32 i, glyphCount = glyphStorage.getGlyphCount();
300 
301     for (i = 0; i < glyphCount; i += 1) {
302         LEPoint advance;
303 
304         glyphStorage.setPosition(i, x, y, success);
305 
306         fFontInstance->getGlyphAdvance(glyphStorage[i], advance);
307         x += advance.fX;
308         y += advance.fY;
309     }
310 
311     glyphStorage.setPosition(glyphCount, x, y, success);
312 }
313 
adjustGlyphPositions(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,LEGlyphStorage & glyphStorage,LEErrorCode & success)314 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool  reverse,
315                                         LEGlyphStorage &glyphStorage, LEErrorCode &success)
316 {
317     if (LE_FAILURE(success)) {
318         return;
319     }
320 
321     if (chars == NULL || offset < 0 || count < 0) {
322         success = LE_ILLEGAL_ARGUMENT_ERROR;
323         return;
324     }
325 
326     GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
327     CanonMarkFilter filter(gdefTable);
328 
329     adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
330 
331     if (fTypoFlags & 0x1) { /* kerning enabled */
332       static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG;
333 
334       KernTable kt(fFontInstance, getFontTable(kernTableTag));
335       kt.process(glyphStorage);
336     }
337 
338     // default is no adjustments
339     return;
340 }
341 
adjustMarkGlyphs(LEGlyphStorage & glyphStorage,LEGlyphFilter * markFilter,LEErrorCode & success)342 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
343 {
344     float xAdjust = 0;
345     le_int32 p, glyphCount = glyphStorage.getGlyphCount();
346 
347     if (LE_FAILURE(success)) {
348         return;
349     }
350 
351     if (markFilter == NULL) {
352         success = LE_ILLEGAL_ARGUMENT_ERROR;
353         return;
354     }
355 
356     float ignore, prev;
357 
358     glyphStorage.getGlyphPosition(0, prev, ignore, success);
359 
360     for (p = 0; p < glyphCount; p += 1) {
361         float next, xAdvance;
362 
363         glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
364 
365         xAdvance = next - prev;
366         glyphStorage.adjustPosition(p, xAdjust, 0, success);
367 
368         if (markFilter->accept(glyphStorage[p])) {
369             xAdjust -= xAdvance;
370         }
371 
372         prev = next;
373     }
374 
375     glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
376 }
377 
adjustMarkGlyphs(const LEUnicode chars[],le_int32 charCount,le_bool reverse,LEGlyphStorage & glyphStorage,LEGlyphFilter * markFilter,LEErrorCode & success)378 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
379 {
380     float xAdjust = 0;
381     le_int32 c = 0, direction = 1, p;
382     le_int32 glyphCount = glyphStorage.getGlyphCount();
383 
384     if (LE_FAILURE(success)) {
385         return;
386     }
387 
388     if (markFilter == NULL) {
389         success = LE_ILLEGAL_ARGUMENT_ERROR;
390         return;
391     }
392 
393     if (reverse) {
394         c = glyphCount - 1;
395         direction = -1;
396     }
397 
398     float ignore, prev;
399 
400     glyphStorage.getGlyphPosition(0, prev, ignore, success);
401 
402     for (p = 0; p < charCount; p += 1, c += direction) {
403         float next, xAdvance;
404 
405         glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
406 
407         xAdvance = next - prev;
408         glyphStorage.adjustPosition(p, xAdjust, 0, success);
409 
410         if (markFilter->accept(chars[c])) {
411             xAdjust -= xAdvance;
412         }
413 
414         prev = next;
415     }
416 
417     glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
418 }
419 
getFontTable(LETag tableTag) const420 const void *LayoutEngine::getFontTable(LETag tableTag) const
421 {
422     return fFontInstance->getFontTable(tableTag);
423 }
424 
mapCharsToGlyphs(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,le_bool mirror,LEGlyphStorage & glyphStorage,LEErrorCode & success)425 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
426                                     LEGlyphStorage &glyphStorage, LEErrorCode &success)
427 {
428     if (LE_FAILURE(success)) {
429         return;
430     }
431 
432     glyphStorage.allocateGlyphArray(count, reverse, success);
433 
434     DefaultCharMapper charMapper(TRUE, mirror);
435 
436     fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, fFilterZeroWidth, glyphStorage);
437 }
438 
439 // Input: characters, font?
440 // Output: glyphs, positions, char indices
441 // 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)442 le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
443                               float x, float y, LEErrorCode &success)
444 {
445     if (LE_FAILURE(success)) {
446         return 0;
447     }
448 
449     if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
450         success = LE_ILLEGAL_ARGUMENT_ERROR;
451         return 0;
452     }
453 
454     le_int32 glyphCount;
455 
456     if (fGlyphStorage->getGlyphCount() > 0) {
457         fGlyphStorage->reset();
458     }
459 
460     glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success);
461     positionGlyphs(*fGlyphStorage, x, y, success);
462     adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success);
463 
464     return glyphCount;
465 }
466 
reset()467 void LayoutEngine::reset()
468 {
469     fGlyphStorage->reset();
470 }
471 
layoutEngineFactory(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,LEErrorCode & success)472 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success)
473 {
474   // 3 -> kerning and ligatures
475   return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, 3, success);
476 }
477 
layoutEngineFactory(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags,LEErrorCode & success)478 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
479 {
480     static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
481     static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
482 
483     if (LE_FAILURE(success)) {
484         return NULL;
485     }
486 
487     const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag);
488     LayoutEngine *result = NULL;
489     LETag scriptTag   = 0x00000000;
490     LETag languageTag = 0x00000000;
491 
492     if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) {
493         switch (scriptCode) {
494         case bengScriptCode:
495         case devaScriptCode:
496         case gujrScriptCode:
497         case kndaScriptCode:
498         case mlymScriptCode:
499         case oryaScriptCode:
500         case guruScriptCode:
501         case tamlScriptCode:
502         case teluScriptCode:
503         case sinhScriptCode:
504             result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
505             break;
506 
507         case arabScriptCode:
508             result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
509             break;
510 
511         case hangScriptCode:
512             result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
513             break;
514 
515         case haniScriptCode:
516             languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
517 
518             switch (languageCode) {
519             case korLanguageCode:
520             case janLanguageCode:
521             case zhtLanguageCode:
522             case zhsLanguageCode:
523                 if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) {
524                     result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
525                     break;
526                 }
527 
528                 // note: falling through to default case.
529             default:
530                 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
531                 break;
532             }
533 
534             break;
535 
536         case tibtScriptCode:
537             result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
538             break;
539 
540         case khmrScriptCode:
541             result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
542             break;
543 
544         default:
545             result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
546             break;
547         }
548     } else {
549         const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag);
550 
551         if (morphTable != NULL) {
552             result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable);
553         } else {
554             switch (scriptCode) {
555             case bengScriptCode:
556             case devaScriptCode:
557             case gujrScriptCode:
558             case kndaScriptCode:
559             case mlymScriptCode:
560             case oryaScriptCode:
561             case guruScriptCode:
562             case tamlScriptCode:
563             case teluScriptCode:
564             case sinhScriptCode:
565             {
566                 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
567                 break;
568             }
569 
570             case arabScriptCode:
571             //case hebrScriptCode:
572                 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
573                 break;
574 
575             //case hebrScriptCode:
576             //    return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
577 
578             case thaiScriptCode:
579                 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
580                 break;
581 
582             case hangScriptCode:
583                 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
584                 break;
585 
586             default:
587                 result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
588                 break;
589             }
590         }
591     }
592 
593     if (result == NULL) {
594         success = LE_MEMORY_ALLOCATION_ERROR;
595     }
596 
597     return result;
598 }
599 
~LayoutEngine()600 LayoutEngine::~LayoutEngine() {
601     delete fGlyphStorage;
602 }
603 
604 U_NAMESPACE_END
605