]> git.saurik.com Git - apple/icu.git/blame - icuSources/layout/LayoutEngine.cpp
ICU-461.18.tar.gz
[apple/icu.git] / icuSources / layout / LayoutEngine.cpp
CommitLineData
b75a7d8f
A
1
2/*
b75a7d8f 3 *
729e4ab9 4 * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved
b75a7d8f
A
5 *
6 */
7
8#include "LETypes.h"
9#include "LEScripts.h"
10#include "LELanguages.h"
11
12#include "LayoutEngine.h"
13#include "ArabicLayoutEngine.h"
374ca955 14#include "CanonShaping.h"
b75a7d8f 15#include "HanLayoutEngine.h"
73c04bcf 16#include "HangulLayoutEngine.h"
b75a7d8f 17#include "IndicLayoutEngine.h"
73c04bcf 18#include "KhmerLayoutEngine.h"
b75a7d8f 19#include "ThaiLayoutEngine.h"
73c04bcf 20#include "TibetanLayoutEngine.h"
b75a7d8f
A
21#include "GXLayoutEngine.h"
22#include "ScriptAndLanguageTags.h"
374ca955
A
23#include "CharSubstitutionFilter.h"
24
25#include "LEGlyphStorage.h"
b75a7d8f
A
26
27#include "OpenTypeUtilities.h"
28#include "GlyphSubstitutionTables.h"
46f4442e 29#include "GlyphDefinitionTables.h"
b75a7d8f
A
30#include "MorphTables.h"
31
32#include "DefaultCharMapper.h"
33
73c04bcf 34#include "KernTable.h"
b75a7d8f 35
73c04bcf 36U_NAMESPACE_BEGIN
b75a7d8f 37
46f4442e
A
38/* Leave this copyright notice here! It needs to go somewhere in this library. */
39static const char copyright[] = U_COPYRIGHT_STRING;
40
b75a7d8f
A
41const 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
73c04bcf 48const le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars);
b75a7d8f
A
49
50LEUnicode32 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) {
73c04bcf 61 le_int32 index = OpenTypeUtilities::search((le_uint32) ch, (le_uint32 *)DefaultCharMapper::mirroredChars, DefaultCharMapper::mirroredCharsCount);
b75a7d8f
A
62
63 if (mirroredChars[index] == ch) {
73c04bcf 64 return DefaultCharMapper::srahCderorrim[index];
b75a7d8f
A
65 }
66 }
67
68 return ch;
69}
70
374ca955
A
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...
74LEGlyphFilter::~LEGlyphFilter()
75{
76 // nothing to do
77}
b75a7d8f 78
374ca955
A
79CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance)
80 : fFontInstance(fontInstance)
b75a7d8f 81{
374ca955 82 // nothing to do
b75a7d8f
A
83}
84
374ca955 85CharSubstitutionFilter::~CharSubstitutionFilter()
b75a7d8f 86{
374ca955
A
87 // nothing to do
88}
b75a7d8f 89
46f4442e
A
90class CanonMarkFilter : public UMemory, public LEGlyphFilter
91{
92private:
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
98public:
99 CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable);
100 virtual ~CanonMarkFilter();
101
102 virtual le_bool accept(LEGlyphID glyph) const;
103};
104
105CanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable)
106{
107 classDefTable = gdefTable->getMarkAttachClassDefinitionTable();
108}
109
110CanonMarkFilter::~CanonMarkFilter()
111{
112 // nothing to do?
113}
114
115le_bool CanonMarkFilter::accept(LEGlyphID glyph) const
116{
117 le_int32 glyphClass = classDefTable->getGlyphClass(glyph);
118
119 return glyphClass != 0;
120}
b75a7d8f 121
374ca955 122UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine)
b75a7d8f 123
73c04bcf 124#define ccmpFeatureTag LE_CCMP_FEATURE_TAG
b75a7d8f 125
73c04bcf
A
126#define ccmpFeatureMask 0x80000000UL
127
128#define canonFeatures (ccmpFeatureMask)
129
130static const FeatureMap canonFeatureMap[] =
131{
132 {ccmpFeatureTag, ccmpFeatureMask}
133};
374ca955 134
73c04bcf 135static const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap);
374ca955 136
729e4ab9
A
137LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance,
138 le_int32 scriptCode,
139 le_int32 languageCode,
140 le_int32 typoFlags,
141 LEErrorCode &success)
73c04bcf 142 : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode),
46f4442e 143 fTypoFlags(typoFlags), fFilterZeroWidth(TRUE)
374ca955 144{
729e4ab9
A
145 if (LE_FAILURE(success)) {
146 return;
147 }
148
374ca955 149 fGlyphStorage = new LEGlyphStorage();
729e4ab9
A
150 if (fGlyphStorage == NULL) {
151 success = LE_MEMORY_ALLOCATION_ERROR;
152 }
374ca955
A
153}
154
155le_int32 LayoutEngine::getGlyphCount() const
156{
157 return fGlyphStorage->getGlyphCount();
73c04bcf 158}
374ca955
A
159
160void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
161{
162 fGlyphStorage->getCharIndices(charIndices, indexBase, success);
b75a7d8f
A
163}
164
165void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
166{
374ca955 167 fGlyphStorage->getCharIndices(charIndices, success);
b75a7d8f
A
168}
169
170// Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
171void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
172{
374ca955 173 fGlyphStorage->getGlyphs(glyphs, extraBits, success);
b75a7d8f
A
174}
175
176void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
177{
374ca955 178 fGlyphStorage->getGlyphs(glyphs, success);
b75a7d8f
A
179}
180
181
182void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const
183{
374ca955 184 fGlyphStorage->getGlyphPositions(positions, success);
b75a7d8f
A
185}
186
187void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
374ca955
A
188{
189 fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success);
190}
191
192le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
46f4442e 193 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
b75a7d8f
A
194{
195 if (LE_FAILURE(success)) {
374ca955 196 return 0;
b75a7d8f 197 }
374ca955
A
198
199 if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
200 success = LE_ILLEGAL_ARGUMENT_ERROR;
201 return 0;
b75a7d8f 202 }
374ca955
A
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);
729e4ab9
A
211 if (substitutionFilter == NULL) {
212 success = LE_MEMORY_ALLOCATION_ERROR;
213 return 0;
214 }
215
73c04bcf
A
216 const LEUnicode *inChars = &chars[offset];
217 LEUnicode *reordered = NULL;
218 LEGlyphStorage fakeGlyphStorage;
374ca955 219
73c04bcf
A
220 fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success);
221
222 if (LE_FAILURE(success)) {
729e4ab9 223 delete substitutionFilter;
73c04bcf
A
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) {
729e4ab9 234 delete substitutionFilter;
73c04bcf
A
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);
374ca955
A
244
245 if (LE_FAILURE(success)) {
729e4ab9 246 delete substitutionFilter;
374ca955
A
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) {
73c04bcf
A
256 fakeGlyphStorage[out] = (LEGlyphID) inChars[i];
257 fakeGlyphStorage.setAuxData(out, canonFeatures, success);
374ca955
A
258 }
259
73c04bcf
A
260 if (reordered != NULL) {
261 LE_DELETE_ARRAY(reordered);
262 }
263
729e4ab9
A
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 }
374ca955 270
73c04bcf 271 out = (rightToLeft? outCharCount - 1 : 0);
374ca955 272
46f4442e
A
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
374ca955 281 outChars = LE_NEW_ARRAY(LEUnicode, outCharCount);
729e4ab9
A
282
283 if (outChars == NULL) {
284 delete substitutionFilter;
285 success = LE_MEMORY_ALLOCATION_ERROR;
286 return 0;
287 }
288
374ca955 289 for (i = 0; i < outCharCount; i += 1, out += dir) {
73c04bcf 290 outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]);
374ca955
A
291 }
292
293 delete substitutionFilter;
b75a7d8f 294 }
b75a7d8f 295
374ca955
A
296 return outCharCount;
297}
b75a7d8f
A
298
299le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
374ca955 300 LEGlyphStorage &glyphStorage, LEErrorCode &success)
b75a7d8f
A
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
374ca955
A
311 LEUnicode *outChars = NULL;
312 le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success);
b75a7d8f 313
374ca955 314 if (outChars != NULL) {
46f4442e 315 mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success);
374ca955
A
316 LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
317 } else {
46f4442e 318 mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
374ca955
A
319 }
320
321 return glyphStorage.getGlyphCount();
b75a7d8f
A
322}
323
324// Input: glyphs
325// Output: positions
374ca955 326void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success)
b75a7d8f
A
327{
328 if (LE_FAILURE(success)) {
329 return;
330 }
331
374ca955 332 glyphStorage.allocatePositions(success);
b75a7d8f 333
374ca955
A
334 if (LE_FAILURE(success)) {
335 return;
b75a7d8f
A
336 }
337
374ca955 338 le_int32 i, glyphCount = glyphStorage.getGlyphCount();
b75a7d8f
A
339
340 for (i = 0; i < glyphCount; i += 1) {
341 LEPoint advance;
342
374ca955 343 glyphStorage.setPosition(i, x, y, success);
b75a7d8f 344
374ca955 345 fFontInstance->getGlyphAdvance(glyphStorage[i], advance);
b75a7d8f
A
346 x += advance.fX;
347 y += advance.fY;
348 }
349
374ca955 350 glyphStorage.setPosition(glyphCount, x, y, success);
b75a7d8f
A
351}
352
46f4442e 353void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
73c04bcf 354 LEGlyphStorage &glyphStorage, LEErrorCode &success)
374ca955
A
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
46f4442e
A
365 GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
366 CanonMarkFilter filter(gdefTable);
367
368 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
369
73c04bcf
A
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
374ca955
A
377 // default is no adjustments
378 return;
379}
380
381void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
b75a7d8f
A
382{
383 float xAdjust = 0;
374ca955 384 le_int32 p, glyphCount = glyphStorage.getGlyphCount();
b75a7d8f
A
385
386 if (LE_FAILURE(success)) {
387 return;
388 }
389
374ca955 390 if (markFilter == NULL) {
b75a7d8f
A
391 success = LE_ILLEGAL_ARGUMENT_ERROR;
392 return;
393 }
394
374ca955 395 float ignore, prev;
b75a7d8f 396
374ca955 397 glyphStorage.getGlyphPosition(0, prev, ignore, success);
b75a7d8f 398
374ca955
A
399 for (p = 0; p < glyphCount; p += 1) {
400 float next, xAdvance;
401
402 glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
b75a7d8f 403
374ca955
A
404 xAdvance = next - prev;
405 glyphStorage.adjustPosition(p, xAdjust, 0, success);
406
407 if (markFilter->accept(glyphStorage[p])) {
b75a7d8f
A
408 xAdjust -= xAdvance;
409 }
374ca955
A
410
411 prev = next;
b75a7d8f
A
412 }
413
374ca955 414 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
b75a7d8f
A
415}
416
374ca955 417void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
b75a7d8f 418{
374ca955
A
419 float xAdjust = 0;
420 le_int32 c = 0, direction = 1, p;
421 le_int32 glyphCount = glyphStorage.getGlyphCount();
b75a7d8f 422
b75a7d8f
A
423 if (LE_FAILURE(success)) {
424 return;
425 }
426
374ca955 427 if (markFilter == NULL) {
b75a7d8f
A
428 success = LE_ILLEGAL_ARGUMENT_ERROR;
429 return;
430 }
431
374ca955
A
432 if (reverse) {
433 c = glyphCount - 1;
434 direction = -1;
b75a7d8f
A
435 }
436
374ca955 437 float ignore, prev;
b75a7d8f 438
374ca955 439 glyphStorage.getGlyphPosition(0, prev, ignore, success);
b75a7d8f 440
374ca955
A
441 for (p = 0; p < charCount; p += 1, c += direction) {
442 float next, xAdvance;
443
444 glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
b75a7d8f 445
374ca955
A
446 xAdvance = next - prev;
447 glyphStorage.adjustPosition(p, xAdjust, 0, success);
b75a7d8f 448
374ca955
A
449 if (markFilter->accept(chars[c])) {
450 xAdjust -= xAdvance;
b75a7d8f 451 }
374ca955
A
452
453 prev = next;
454 }
455
456 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
457}
458
459const void *LayoutEngine::getFontTable(LETag tableTag) const
460{
461 return fFontInstance->getFontTable(tableTag);
462}
463
46f4442e 464void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
374ca955
A
465 LEGlyphStorage &glyphStorage, LEErrorCode &success)
466{
467 if (LE_FAILURE(success)) {
468 return;
b75a7d8f
A
469 }
470
374ca955 471 glyphStorage.allocateGlyphArray(count, reverse, success);
b75a7d8f 472
374ca955
A
473 DefaultCharMapper charMapper(TRUE, mirror);
474
46f4442e 475 fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, fFilterZeroWidth, glyphStorage);
b75a7d8f
A
476}
477
478// Input: characters, font?
479// Output: glyphs, positions, char indices
480// Returns: number of glyphs
481le_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
374ca955 493 le_int32 glyphCount;
73c04bcf
A
494
495 if (fGlyphStorage->getGlyphCount() > 0) {
496 fGlyphStorage->reset();
497 }
374ca955
A
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);
b75a7d8f 502
374ca955 503 return glyphCount;
b75a7d8f
A
504}
505
506void LayoutEngine::reset()
507{
374ca955 508 fGlyphStorage->reset();
b75a7d8f
A
509}
510
511LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success)
73c04bcf
A
512{
513 // 3 -> kerning and ligatures
514 return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, 3, success);
515}
516
517LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
b75a7d8f 518{
374ca955
A
519 static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
520 static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
b75a7d8f
A
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;
729e4ab9 530 LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode);
b75a7d8f 531
729e4ab9
A
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))) {
b75a7d8f
A
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:
73c04bcf 549 case sinhScriptCode:
729e4ab9 550 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success);
b75a7d8f
A
551 break;
552
553 case arabScriptCode:
729e4ab9 554 result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
73c04bcf
A
555 break;
556
557 case hangScriptCode:
729e4ab9 558 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
b75a7d8f
A
559 break;
560
561 case haniScriptCode:
562 languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
563
564 switch (languageCode) {
565 case korLanguageCode:
566 case janLanguageCode:
567 case zhtLanguageCode:
568 case zhsLanguageCode:
374ca955 569 if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) {
729e4ab9 570 result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
b75a7d8f
A
571 break;
572 }
573
574 // note: falling through to default case.
575 default:
729e4ab9 576 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
b75a7d8f
A
577 break;
578 }
579
580 break;
581
73c04bcf 582 case tibtScriptCode:
729e4ab9 583 result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
73c04bcf
A
584 break;
585
586 case khmrScriptCode:
729e4ab9 587 result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
73c04bcf
A
588 break;
589
b75a7d8f 590 default:
729e4ab9 591 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
b75a7d8f
A
592 break;
593 }
594 } else {
595 const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag);
596
597 if (morphTable != NULL) {
729e4ab9 598 result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable, success);
b75a7d8f
A
599 } else {
600 switch (scriptCode) {
601 case bengScriptCode:
602 case devaScriptCode:
603 case gujrScriptCode:
604 case kndaScriptCode:
605 case mlymScriptCode:
606 case oryaScriptCode:
607 case guruScriptCode:
608 case tamlScriptCode:
609 case teluScriptCode:
73c04bcf 610 case sinhScriptCode:
b75a7d8f 611 {
729e4ab9 612 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
b75a7d8f
A
613 break;
614 }
615
616 case arabScriptCode:
374ca955 617 //case hebrScriptCode:
729e4ab9 618 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
b75a7d8f
A
619 break;
620
621 //case hebrScriptCode:
73c04bcf 622 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
b75a7d8f
A
623
624 case thaiScriptCode:
729e4ab9 625 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
b75a7d8f
A
626 break;
627
46f4442e 628 case hangScriptCode:
729e4ab9 629 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
46f4442e
A
630 break;
631
b75a7d8f 632 default:
729e4ab9 633 result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
b75a7d8f
A
634 break;
635 }
636 }
637 }
638
729e4ab9
A
639 if (result && LE_FAILURE(success)) {
640 delete result;
641 result = NULL;
642 }
643
b75a7d8f
A
644 if (result == NULL) {
645 success = LE_MEMORY_ALLOCATION_ERROR;
646 }
647
648 return result;
649}
650
651LayoutEngine::~LayoutEngine() {
73c04bcf 652 delete fGlyphStorage;
b75a7d8f
A
653}
654
655U_NAMESPACE_END