]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | |
2 | /* | |
b75a7d8f | 3 | * |
73c04bcf | 4 | * (C) Copyright IBM Corp. 1998-2006 - 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" | |
29 | #include "MorphTables.h" | |
30 | ||
31 | #include "DefaultCharMapper.h" | |
32 | ||
73c04bcf | 33 | #include "KernTable.h" |
b75a7d8f | 34 | |
73c04bcf | 35 | U_NAMESPACE_BEGIN |
b75a7d8f A |
36 | |
37 | const LEUnicode32 DefaultCharMapper::controlChars[] = { | |
38 | 0x0009, 0x000A, 0x000D, | |
39 | /*0x200C, 0x200D,*/ 0x200E, 0x200F, | |
40 | 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, | |
41 | 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F | |
42 | }; | |
43 | ||
73c04bcf | 44 | const le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars); |
b75a7d8f A |
45 | |
46 | LEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch) const | |
47 | { | |
48 | if (fFilterControls) { | |
49 | le_int32 index = OpenTypeUtilities::search((le_uint32)ch, (le_uint32 *)controlChars, controlCharsCount); | |
50 | ||
51 | if (controlChars[index] == ch) { | |
52 | return 0xFFFF; | |
53 | } | |
54 | } | |
55 | ||
56 | if (fMirror) { | |
73c04bcf | 57 | le_int32 index = OpenTypeUtilities::search((le_uint32) ch, (le_uint32 *)DefaultCharMapper::mirroredChars, DefaultCharMapper::mirroredCharsCount); |
b75a7d8f A |
58 | |
59 | if (mirroredChars[index] == ch) { | |
73c04bcf | 60 | return DefaultCharMapper::srahCderorrim[index]; |
b75a7d8f A |
61 | } |
62 | } | |
63 | ||
64 | return ch; | |
65 | } | |
66 | ||
374ca955 A |
67 | // This is here to get it out of LEGlyphFilter.h. |
68 | // No particular reason to put it here, other than | |
69 | // this is a good central location... | |
70 | LEGlyphFilter::~LEGlyphFilter() | |
71 | { | |
72 | // nothing to do | |
73 | } | |
b75a7d8f | 74 | |
374ca955 A |
75 | CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance) |
76 | : fFontInstance(fontInstance) | |
b75a7d8f | 77 | { |
374ca955 | 78 | // nothing to do |
b75a7d8f A |
79 | } |
80 | ||
374ca955 | 81 | CharSubstitutionFilter::~CharSubstitutionFilter() |
b75a7d8f | 82 | { |
374ca955 A |
83 | // nothing to do |
84 | } | |
b75a7d8f | 85 | |
b75a7d8f | 86 | |
374ca955 | 87 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine) |
b75a7d8f | 88 | |
73c04bcf | 89 | #define ccmpFeatureTag LE_CCMP_FEATURE_TAG |
b75a7d8f | 90 | |
73c04bcf A |
91 | #define ccmpFeatureMask 0x80000000UL |
92 | ||
93 | #define canonFeatures (ccmpFeatureMask) | |
94 | ||
95 | static const FeatureMap canonFeatureMap[] = | |
96 | { | |
97 | {ccmpFeatureTag, ccmpFeatureMask} | |
98 | }; | |
374ca955 | 99 | |
73c04bcf | 100 | static const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap); |
374ca955 | 101 | |
73c04bcf A |
102 | LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags) |
103 | : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode), | |
104 | fTypoFlags(typoFlags) | |
374ca955 A |
105 | { |
106 | fGlyphStorage = new LEGlyphStorage(); | |
107 | } | |
108 | ||
109 | le_int32 LayoutEngine::getGlyphCount() const | |
110 | { | |
111 | return fGlyphStorage->getGlyphCount(); | |
73c04bcf | 112 | } |
374ca955 A |
113 | |
114 | void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const | |
115 | { | |
116 | fGlyphStorage->getCharIndices(charIndices, indexBase, success); | |
b75a7d8f A |
117 | } |
118 | ||
119 | void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const | |
120 | { | |
374ca955 | 121 | fGlyphStorage->getCharIndices(charIndices, success); |
b75a7d8f A |
122 | } |
123 | ||
124 | // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits | |
125 | void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const | |
126 | { | |
374ca955 | 127 | fGlyphStorage->getGlyphs(glyphs, extraBits, success); |
b75a7d8f A |
128 | } |
129 | ||
130 | void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const | |
131 | { | |
374ca955 | 132 | fGlyphStorage->getGlyphs(glyphs, success); |
b75a7d8f A |
133 | } |
134 | ||
135 | ||
136 | void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const | |
137 | { | |
374ca955 | 138 | fGlyphStorage->getGlyphPositions(positions, success); |
b75a7d8f A |
139 | } |
140 | ||
141 | void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const | |
374ca955 A |
142 | { |
143 | fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success); | |
144 | } | |
145 | ||
146 | le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, | |
73c04bcf | 147 | LEUnicode *&outChars, LEGlyphStorage &/*glyphStorage*/, LEErrorCode &success) |
b75a7d8f A |
148 | { |
149 | if (LE_FAILURE(success)) { | |
374ca955 | 150 | return 0; |
b75a7d8f | 151 | } |
374ca955 A |
152 | |
153 | if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { | |
154 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
155 | return 0; | |
b75a7d8f | 156 | } |
374ca955 A |
157 | |
158 | const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; | |
159 | LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); | |
160 | LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); | |
161 | le_int32 i, dir = 1, out = 0, outCharCount = count; | |
162 | ||
163 | if (canonGSUBTable->coversScript(scriptTag)) { | |
164 | CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); | |
73c04bcf A |
165 | const LEUnicode *inChars = &chars[offset]; |
166 | LEUnicode *reordered = NULL; | |
167 | LEGlyphStorage fakeGlyphStorage; | |
374ca955 | 168 | |
73c04bcf A |
169 | fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); |
170 | ||
171 | if (LE_FAILURE(success)) { | |
172 | return 0; | |
173 | } | |
174 | ||
175 | // This is the cheapest way to get mark reordering only for Hebrew. | |
176 | // We could just do the mark reordering for all scripts, but most | |
177 | // of them probably don't need it... | |
178 | if (fScriptCode == hebrScriptCode) { | |
179 | reordered = LE_NEW_ARRAY(LEUnicode, count); | |
180 | ||
181 | if (reordered == NULL) { | |
182 | success = LE_MEMORY_ALLOCATION_ERROR; | |
183 | return 0; | |
184 | } | |
185 | ||
186 | CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); | |
187 | inChars = reordered; | |
188 | } | |
189 | ||
190 | fakeGlyphStorage.allocateAuxData(success); | |
374ca955 A |
191 | |
192 | if (LE_FAILURE(success)) { | |
193 | return 0; | |
194 | } | |
195 | ||
196 | if (rightToLeft) { | |
197 | out = count - 1; | |
198 | dir = -1; | |
199 | } | |
200 | ||
201 | for (i = 0; i < count; i += 1, out += dir) { | |
73c04bcf A |
202 | fakeGlyphStorage[out] = (LEGlyphID) inChars[i]; |
203 | fakeGlyphStorage.setAuxData(out, canonFeatures, success); | |
374ca955 A |
204 | } |
205 | ||
73c04bcf A |
206 | if (reordered != NULL) { |
207 | LE_DELETE_ARRAY(reordered); | |
208 | } | |
209 | ||
210 | outCharCount = canonGSUBTable->process(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE); | |
374ca955 | 211 | |
73c04bcf | 212 | out = (rightToLeft? outCharCount - 1 : 0); |
374ca955 A |
213 | |
214 | outChars = LE_NEW_ARRAY(LEUnicode, outCharCount); | |
215 | for (i = 0; i < outCharCount; i += 1, out += dir) { | |
73c04bcf | 216 | outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]); |
374ca955 A |
217 | } |
218 | ||
219 | delete substitutionFilter; | |
b75a7d8f | 220 | } |
b75a7d8f | 221 | |
374ca955 A |
222 | return outCharCount; |
223 | } | |
b75a7d8f A |
224 | |
225 | le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, | |
374ca955 | 226 | LEGlyphStorage &glyphStorage, LEErrorCode &success) |
b75a7d8f A |
227 | { |
228 | if (LE_FAILURE(success)) { | |
229 | return 0; | |
230 | } | |
231 | ||
232 | if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { | |
233 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
234 | return 0; | |
235 | } | |
236 | ||
374ca955 A |
237 | LEUnicode *outChars = NULL; |
238 | le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success); | |
b75a7d8f | 239 | |
374ca955 | 240 | if (outChars != NULL) { |
73c04bcf | 241 | mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, TRUE, glyphStorage, success); |
374ca955 A |
242 | LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... |
243 | } else { | |
73c04bcf | 244 | mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, TRUE, glyphStorage, success); |
374ca955 A |
245 | } |
246 | ||
247 | return glyphStorage.getGlyphCount(); | |
b75a7d8f A |
248 | } |
249 | ||
250 | // Input: glyphs | |
251 | // Output: positions | |
374ca955 | 252 | void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success) |
b75a7d8f A |
253 | { |
254 | if (LE_FAILURE(success)) { | |
255 | return; | |
256 | } | |
257 | ||
374ca955 | 258 | glyphStorage.allocatePositions(success); |
b75a7d8f | 259 | |
374ca955 A |
260 | if (LE_FAILURE(success)) { |
261 | return; | |
b75a7d8f A |
262 | } |
263 | ||
374ca955 | 264 | le_int32 i, glyphCount = glyphStorage.getGlyphCount(); |
b75a7d8f A |
265 | |
266 | for (i = 0; i < glyphCount; i += 1) { | |
267 | LEPoint advance; | |
268 | ||
374ca955 | 269 | glyphStorage.setPosition(i, x, y, success); |
b75a7d8f | 270 | |
374ca955 | 271 | fFontInstance->getGlyphAdvance(glyphStorage[i], advance); |
b75a7d8f A |
272 | x += advance.fX; |
273 | y += advance.fY; | |
274 | } | |
275 | ||
374ca955 | 276 | glyphStorage.setPosition(glyphCount, x, y, success); |
b75a7d8f A |
277 | } |
278 | ||
374ca955 | 279 | void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool /*reverse*/, |
73c04bcf | 280 | LEGlyphStorage &glyphStorage, LEErrorCode &success) |
374ca955 A |
281 | { |
282 | if (LE_FAILURE(success)) { | |
283 | return; | |
284 | } | |
285 | ||
286 | if (chars == NULL || offset < 0 || count < 0) { | |
287 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
288 | return; | |
289 | } | |
290 | ||
73c04bcf A |
291 | if (fTypoFlags & 0x1) { /* kerning enabled */ |
292 | static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; | |
293 | ||
294 | KernTable kt(fFontInstance, getFontTable(kernTableTag)); | |
295 | kt.process(glyphStorage); | |
296 | } | |
297 | ||
374ca955 A |
298 | // default is no adjustments |
299 | return; | |
300 | } | |
301 | ||
302 | void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success) | |
b75a7d8f A |
303 | { |
304 | float xAdjust = 0; | |
374ca955 | 305 | le_int32 p, glyphCount = glyphStorage.getGlyphCount(); |
b75a7d8f A |
306 | |
307 | if (LE_FAILURE(success)) { | |
308 | return; | |
309 | } | |
310 | ||
374ca955 | 311 | if (markFilter == NULL) { |
b75a7d8f A |
312 | success = LE_ILLEGAL_ARGUMENT_ERROR; |
313 | return; | |
314 | } | |
315 | ||
374ca955 | 316 | float ignore, prev; |
b75a7d8f | 317 | |
374ca955 | 318 | glyphStorage.getGlyphPosition(0, prev, ignore, success); |
b75a7d8f | 319 | |
374ca955 A |
320 | for (p = 0; p < glyphCount; p += 1) { |
321 | float next, xAdvance; | |
322 | ||
323 | glyphStorage.getGlyphPosition(p + 1, next, ignore, success); | |
b75a7d8f | 324 | |
374ca955 A |
325 | xAdvance = next - prev; |
326 | glyphStorage.adjustPosition(p, xAdjust, 0, success); | |
327 | ||
328 | if (markFilter->accept(glyphStorage[p])) { | |
b75a7d8f A |
329 | xAdjust -= xAdvance; |
330 | } | |
374ca955 A |
331 | |
332 | prev = next; | |
b75a7d8f A |
333 | } |
334 | ||
374ca955 | 335 | glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); |
b75a7d8f A |
336 | } |
337 | ||
374ca955 | 338 | void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success) |
b75a7d8f | 339 | { |
374ca955 A |
340 | float xAdjust = 0; |
341 | le_int32 c = 0, direction = 1, p; | |
342 | le_int32 glyphCount = glyphStorage.getGlyphCount(); | |
b75a7d8f | 343 | |
b75a7d8f A |
344 | if (LE_FAILURE(success)) { |
345 | return; | |
346 | } | |
347 | ||
374ca955 | 348 | if (markFilter == NULL) { |
b75a7d8f A |
349 | success = LE_ILLEGAL_ARGUMENT_ERROR; |
350 | return; | |
351 | } | |
352 | ||
374ca955 A |
353 | if (reverse) { |
354 | c = glyphCount - 1; | |
355 | direction = -1; | |
b75a7d8f A |
356 | } |
357 | ||
374ca955 | 358 | float ignore, prev; |
b75a7d8f | 359 | |
374ca955 | 360 | glyphStorage.getGlyphPosition(0, prev, ignore, success); |
b75a7d8f | 361 | |
374ca955 A |
362 | for (p = 0; p < charCount; p += 1, c += direction) { |
363 | float next, xAdvance; | |
364 | ||
365 | glyphStorage.getGlyphPosition(p + 1, next, ignore, success); | |
b75a7d8f | 366 | |
374ca955 A |
367 | xAdvance = next - prev; |
368 | glyphStorage.adjustPosition(p, xAdjust, 0, success); | |
b75a7d8f | 369 | |
374ca955 A |
370 | if (markFilter->accept(chars[c])) { |
371 | xAdjust -= xAdvance; | |
b75a7d8f | 372 | } |
374ca955 A |
373 | |
374 | prev = next; | |
375 | } | |
376 | ||
377 | glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); | |
378 | } | |
379 | ||
380 | const void *LayoutEngine::getFontTable(LETag tableTag) const | |
381 | { | |
382 | return fFontInstance->getFontTable(tableTag); | |
383 | } | |
384 | ||
73c04bcf | 385 | void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, le_bool filterZeroWidth, |
374ca955 A |
386 | LEGlyphStorage &glyphStorage, LEErrorCode &success) |
387 | { | |
388 | if (LE_FAILURE(success)) { | |
389 | return; | |
b75a7d8f A |
390 | } |
391 | ||
374ca955 | 392 | glyphStorage.allocateGlyphArray(count, reverse, success); |
b75a7d8f | 393 | |
374ca955 A |
394 | DefaultCharMapper charMapper(TRUE, mirror); |
395 | ||
73c04bcf | 396 | fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, filterZeroWidth, glyphStorage); |
b75a7d8f A |
397 | } |
398 | ||
399 | // Input: characters, font? | |
400 | // Output: glyphs, positions, char indices | |
401 | // Returns: number of glyphs | |
402 | le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, | |
403 | float x, float y, LEErrorCode &success) | |
404 | { | |
405 | if (LE_FAILURE(success)) { | |
406 | return 0; | |
407 | } | |
408 | ||
409 | if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { | |
410 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
411 | return 0; | |
412 | } | |
413 | ||
374ca955 | 414 | le_int32 glyphCount; |
73c04bcf A |
415 | |
416 | if (fGlyphStorage->getGlyphCount() > 0) { | |
417 | fGlyphStorage->reset(); | |
418 | } | |
374ca955 A |
419 | |
420 | glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success); | |
421 | positionGlyphs(*fGlyphStorage, x, y, success); | |
422 | adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success); | |
b75a7d8f | 423 | |
374ca955 | 424 | return glyphCount; |
b75a7d8f A |
425 | } |
426 | ||
427 | void LayoutEngine::reset() | |
428 | { | |
374ca955 | 429 | fGlyphStorage->reset(); |
b75a7d8f A |
430 | } |
431 | ||
432 | LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success) | |
73c04bcf A |
433 | { |
434 | // 3 -> kerning and ligatures | |
435 | return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, 3, success); | |
436 | } | |
437 | ||
438 | LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) | |
b75a7d8f | 439 | { |
374ca955 A |
440 | static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG; |
441 | static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG; | |
b75a7d8f A |
442 | |
443 | if (LE_FAILURE(success)) { | |
444 | return NULL; | |
445 | } | |
446 | ||
447 | const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag); | |
448 | LayoutEngine *result = NULL; | |
449 | LETag scriptTag = 0x00000000; | |
450 | LETag languageTag = 0x00000000; | |
451 | ||
452 | if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) { | |
453 | switch (scriptCode) { | |
454 | case bengScriptCode: | |
455 | case devaScriptCode: | |
456 | case gujrScriptCode: | |
457 | case kndaScriptCode: | |
458 | case mlymScriptCode: | |
459 | case oryaScriptCode: | |
460 | case guruScriptCode: | |
461 | case tamlScriptCode: | |
462 | case teluScriptCode: | |
73c04bcf A |
463 | case sinhScriptCode: |
464 | result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); | |
b75a7d8f A |
465 | break; |
466 | ||
467 | case arabScriptCode: | |
73c04bcf A |
468 | result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); |
469 | break; | |
470 | ||
471 | case hangScriptCode: | |
472 | result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); | |
b75a7d8f A |
473 | break; |
474 | ||
475 | case haniScriptCode: | |
476 | languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode); | |
477 | ||
478 | switch (languageCode) { | |
479 | case korLanguageCode: | |
480 | case janLanguageCode: | |
481 | case zhtLanguageCode: | |
482 | case zhsLanguageCode: | |
374ca955 | 483 | if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) { |
73c04bcf | 484 | result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); |
b75a7d8f A |
485 | break; |
486 | } | |
487 | ||
488 | // note: falling through to default case. | |
489 | default: | |
73c04bcf | 490 | result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); |
b75a7d8f A |
491 | break; |
492 | } | |
493 | ||
494 | break; | |
495 | ||
73c04bcf A |
496 | case tibtScriptCode: |
497 | result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); | |
498 | break; | |
499 | ||
500 | case khmrScriptCode: | |
501 | result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); | |
502 | break; | |
503 | ||
b75a7d8f | 504 | default: |
73c04bcf | 505 | result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); |
b75a7d8f A |
506 | break; |
507 | } | |
508 | } else { | |
509 | const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); | |
510 | ||
511 | if (morphTable != NULL) { | |
512 | result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable); | |
513 | } else { | |
514 | switch (scriptCode) { | |
515 | case bengScriptCode: | |
516 | case devaScriptCode: | |
517 | case gujrScriptCode: | |
518 | case kndaScriptCode: | |
519 | case mlymScriptCode: | |
520 | case oryaScriptCode: | |
521 | case guruScriptCode: | |
522 | case tamlScriptCode: | |
523 | case teluScriptCode: | |
73c04bcf | 524 | case sinhScriptCode: |
b75a7d8f | 525 | { |
73c04bcf | 526 | result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); |
b75a7d8f A |
527 | break; |
528 | } | |
529 | ||
530 | case arabScriptCode: | |
374ca955 | 531 | //case hebrScriptCode: |
73c04bcf | 532 | result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); |
b75a7d8f A |
533 | break; |
534 | ||
535 | //case hebrScriptCode: | |
73c04bcf | 536 | // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); |
b75a7d8f A |
537 | |
538 | case thaiScriptCode: | |
73c04bcf | 539 | result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); |
b75a7d8f A |
540 | break; |
541 | ||
542 | default: | |
73c04bcf | 543 | result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); |
b75a7d8f A |
544 | break; |
545 | } | |
546 | } | |
547 | } | |
548 | ||
549 | if (result == NULL) { | |
550 | success = LE_MEMORY_ALLOCATION_ERROR; | |
551 | } | |
552 | ||
553 | return result; | |
554 | } | |
555 | ||
556 | LayoutEngine::~LayoutEngine() { | |
73c04bcf | 557 | delete fGlyphStorage; |
b75a7d8f A |
558 | } |
559 | ||
560 | U_NAMESPACE_END |