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