1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26
27 /*
28 *
29 * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
30 *
31 */
32
33 #include "LETypes.h"
34 #include "LEScripts.h"
35 #include "LELanguages.h"
36 #include "LESwaps.h"
37
38 #include "LayoutEngine.h"
39 #include "ArabicLayoutEngine.h"
40 #include "CanonShaping.h"
41 #include "HanLayoutEngine.h"
42 #include "HangulLayoutEngine.h"
43 #include "IndicLayoutEngine.h"
44 #include "KhmerLayoutEngine.h"
45 #include "ThaiLayoutEngine.h"
46 #include "TibetanLayoutEngine.h"
47 #include "GXLayoutEngine.h"
48 #include "GXLayoutEngine2.h"
49
50 #include "ScriptAndLanguageTags.h"
51 #include "CharSubstitutionFilter.h"
52
53 #include "LEGlyphStorage.h"
54
55 #include "OpenTypeUtilities.h"
56 #include "GlyphSubstitutionTables.h"
57 #include "GlyphDefinitionTables.h"
58 #include "MorphTables.h"
59
60 #include "DefaultCharMapper.h"
61
62 #include "KernTable.h"
63
64 U_NAMESPACE_BEGIN
65
66 /* Leave this copyright notice here! It needs to go somewhere in this library. */
67 static const char copyright[] = U_COPYRIGHT_STRING;
68
69 /* TODO: remove these? */
70 const le_int32 LayoutEngine::kTypoFlagKern = LE_Kerning_FEATURE_FLAG;
71 const le_int32 LayoutEngine::kTypoFlagLiga = LE_Ligatures_FEATURE_FLAG;
72
73 const LEUnicode32 DefaultCharMapper::controlChars[] = {
74 0x0009, 0x000A, 0x000D,
75 /*0x200C, 0x200D,*/ 0x200E, 0x200F,
76 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
77 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
78 };
79
80 const le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars);
81
82 const LEUnicode32 DefaultCharMapper::controlCharsZWJ[] = {
83 0x0009, 0x000A, 0x000D,
84 0x200C, 0x200D, 0x200E, 0x200F,
85 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
86 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
87 };
88
89 const le_int32 DefaultCharMapper::controlCharsZWJCount = LE_ARRAY_SIZE(controlCharsZWJ);
90
mapChar(LEUnicode32 ch) const91 LEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch) const
92 {
93 if (fZWJ) {
94 if (ch < 0x20) {
95 if (ch == 0x0a || ch == 0x0d || ch == 0x09) {
96 return 0xffff;
97 }
98 } else if (ch >= 0x200c && ch <= 0x206f) {
99 le_int32 index = OpenTypeUtilities::search((le_uint32)ch,
100 (le_uint32 *)controlCharsZWJ,
101 controlCharsZWJCount);
102 if (controlCharsZWJ[index] == ch) {
103 return 0xffff;
104 }
105 }
106 return ch; // note ZWJ bypasses fFilterControls and fMirror
107 }
108
109 if (fFilterControls) {
110 le_int32 index = OpenTypeUtilities::search((le_uint32)ch, (le_uint32 *)controlChars, controlCharsCount);
111
112 if (controlChars[index] == ch) {
113 return 0xFFFF;
114 }
115 }
116
117 if (fMirror) {
118 le_int32 index = OpenTypeUtilities::search((le_uint32) ch, (le_uint32 *)DefaultCharMapper::mirroredChars, DefaultCharMapper::mirroredCharsCount);
119
120 if (mirroredChars[index] == ch) {
121 return DefaultCharMapper::srahCderorrim[index];
122 }
123 }
124
125 return ch;
126 }
127
128 // This is here to get it out of LEGlyphFilter.h.
129 // No particular reason to put it here, other than
130 // this is a good central location...
~LEGlyphFilter()131 LEGlyphFilter::~LEGlyphFilter()
132 {
133 // nothing to do
134 }
135
CharSubstitutionFilter(const LEFontInstance * fontInstance)136 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance)
137 : fFontInstance(fontInstance)
138 {
139 // nothing to do
140 }
141
~CharSubstitutionFilter()142 CharSubstitutionFilter::~CharSubstitutionFilter()
143 {
144 // nothing to do
145 }
146
147 class CanonMarkFilter : public UMemory, public LEGlyphFilter
148 {
149 private:
150 const LEReferenceTo<GlyphClassDefinitionTable> classDefTable;
151
152 CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class
153 CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class
154
155 public:
156 CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success);
157 virtual ~CanonMarkFilter();
158
159 virtual le_bool accept(LEGlyphID glyph, LEErrorCode &success) const;
160 };
161
CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> & gdefTable,LEErrorCode & success)162 CanonMarkFilter::CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success)
163 : classDefTable(gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success))
164 {
165 }
166
~CanonMarkFilter()167 CanonMarkFilter::~CanonMarkFilter()
168 {
169 // nothing to do?
170 }
171
accept(LEGlyphID glyph,LEErrorCode & success) const172 le_bool CanonMarkFilter::accept(LEGlyphID glyph, LEErrorCode &success) const
173 {
174 le_int32 glyphClass = classDefTable->getGlyphClass(classDefTable, glyph, success);
175 if(LE_FAILURE(success)) return false;
176 return glyphClass != 0;
177 }
178
179 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine)
180
181 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
182
183 #define ccmpFeatureMask 0x80000000UL
184
185 #define canonFeatures (ccmpFeatureMask)
186
187 static const FeatureMap canonFeatureMap[] =
188 {
189 {ccmpFeatureTag, ccmpFeatureMask}
190 };
191
192 static const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap);
193
LayoutEngine(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags,LEErrorCode & success)194 LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance,
195 le_int32 scriptCode,
196 le_int32 languageCode,
197 le_int32 typoFlags,
198 LEErrorCode &success)
199 : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode),
200 fTypoFlags(typoFlags), fFilterZeroWidth(TRUE)
201 {
202 if (LE_FAILURE(success)) {
203 return;
204 }
205
206 fGlyphStorage = new LEGlyphStorage();
207 if (fGlyphStorage == NULL) {
208 success = LE_MEMORY_ALLOCATION_ERROR;
209 }
210 }
211
getGlyphCount() const212 le_int32 LayoutEngine::getGlyphCount() const
213 {
214 return fGlyphStorage->getGlyphCount();
215 }
216
getCharIndices(le_int32 charIndices[],le_int32 indexBase,LEErrorCode & success) const217 void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
218 {
219 fGlyphStorage->getCharIndices(charIndices, indexBase, success);
220 }
221
getCharIndices(le_int32 charIndices[],LEErrorCode & success) const222 void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
223 {
224 fGlyphStorage->getCharIndices(charIndices, success);
225 }
226
227 // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
getGlyphs(le_uint32 glyphs[],le_uint32 extraBits,LEErrorCode & success) const228 void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
229 {
230 fGlyphStorage->getGlyphs(glyphs, extraBits, success);
231 }
232
getGlyphs(LEGlyphID glyphs[],LEErrorCode & success) const233 void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
234 {
235 fGlyphStorage->getGlyphs(glyphs, success);
236 }
237
238
getGlyphPositions(float positions[],LEErrorCode & success) const239 void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const
240 {
241 fGlyphStorage->getGlyphPositions(positions, success);
242 }
243
getGlyphPosition(le_int32 glyphIndex,float & x,float & y,LEErrorCode & success) const244 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
245 {
246 fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success);
247 }
248
characterProcessing(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEUnicode * & outChars,LEGlyphStorage & glyphStorage,LEErrorCode & success)249 le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
250 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
251 {
252 if (LE_FAILURE(success)) {
253 return 0;
254 }
255
256 if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
257 success = LE_ILLEGAL_ARGUMENT_ERROR;
258 return 0;
259 }
260
261 if ((fTypoFlags & LE_NoCanon_FEATURE_FLAG) == 0) { // no canonical processing
262 return count;
263 }
264
265 LEReferenceTo<GlyphSubstitutionTableHeader> canonGSUBTable(LETableReference::kStaticData,
266 (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable,
267 CanonShaping::glyphSubstitutionTableLen);
268 LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode);
269 LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode);
270 le_int32 i, dir = 1, out = 0, outCharCount = count;
271
272 if (canonGSUBTable->coversScript(canonGSUBTable,scriptTag, success) || LE_SUCCESS(success)) {
273 CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance);
274 if (substitutionFilter == NULL) {
275 success = LE_MEMORY_ALLOCATION_ERROR;
276 return 0;
277 }
278
279 const LEUnicode *inChars = &chars[offset];
280 LEUnicode *reordered = NULL;
281 LEGlyphStorage fakeGlyphStorage;
282
283 fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success);
284
285 if (LE_FAILURE(success)) {
286 delete substitutionFilter;
287 return 0;
288 }
289
290 // This is the cheapest way to get mark reordering only for Hebrew.
291 // We could just do the mark reordering for all scripts, but most
292 // of them probably don't need it...
293 if (fScriptCode == hebrScriptCode) {
294 reordered = LE_NEW_ARRAY(LEUnicode, count);
295
296 if (reordered == NULL) {
297 delete substitutionFilter;
298 success = LE_MEMORY_ALLOCATION_ERROR;
299 return 0;
300 }
301
302 CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage);
303 inChars = reordered;
304 }
305
306 fakeGlyphStorage.allocateAuxData(success);
307
308 if (LE_FAILURE(success)) {
309 delete substitutionFilter;
310 return 0;
311 }
312
313 if (rightToLeft) {
314 out = count - 1;
315 dir = -1;
316 }
317
318 for (i = 0; i < count; i += 1, out += dir) {
319 fakeGlyphStorage[out] = (LEGlyphID) inChars[i];
320 fakeGlyphStorage.setAuxData(out, canonFeatures, success);
321 }
322
323 if (reordered != NULL) {
324 LE_DELETE_ARRAY(reordered);
325 }
326
327 const LEReferenceTo<GlyphDefinitionTableHeader> noGDEF; // empty gdef header
328 outCharCount = canonGSUBTable->process(canonGSUBTable, fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, noGDEF, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success);
329
330 if (LE_FAILURE(success)) {
331 delete substitutionFilter;
332 return 0;
333 }
334
335 out = (rightToLeft? outCharCount - 1 : 0);
336
337 /*
338 * The char indices array in fakeGlyphStorage has the correct mapping
339 * back to the original input characters. Save it in glyphStorage. The
340 * subsequent call to glyphStoratge.allocateGlyphArray will keep this
341 * array rather than allocating and initializing a new one.
342 */
343 glyphStorage.adoptCharIndicesArray(fakeGlyphStorage);
344
345 outChars = LE_NEW_ARRAY(LEUnicode, outCharCount);
346
347 if (outChars == NULL) {
348 delete substitutionFilter;
349 success = LE_MEMORY_ALLOCATION_ERROR;
350 return 0;
351 }
352
353 for (i = 0; i < outCharCount; i += 1, out += dir) {
354 outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]);
355 }
356
357 delete substitutionFilter;
358 }
359
360 return outCharCount;
361 }
362
computeGlyphs(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEGlyphStorage & glyphStorage,LEErrorCode & success)363 le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
364 LEGlyphStorage &glyphStorage, LEErrorCode &success)
365 {
366 if (LE_FAILURE(success)) {
367 return 0;
368 }
369
370 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
371 success = LE_ILLEGAL_ARGUMENT_ERROR;
372 return 0;
373 }
374
375 LEUnicode *outChars = NULL;
376 le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success);
377
378 if (outChars != NULL) {
379 mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success);
380 LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
381 } else {
382 mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
383 }
384
385 return glyphStorage.getGlyphCount();
386 }
387
388 // Input: glyphs
389 // Output: positions
positionGlyphs(LEGlyphStorage & glyphStorage,float x,float y,LEErrorCode & success)390 void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success)
391 {
392 if (LE_FAILURE(success)) {
393 return;
394 }
395
396 glyphStorage.allocatePositions(success);
397
398 if (LE_FAILURE(success)) {
399 return;
400 }
401
402 le_int32 i, glyphCount = glyphStorage.getGlyphCount();
403
404 for (i = 0; i < glyphCount; i += 1) {
405 LEPoint advance;
406
407 glyphStorage.setPosition(i, x, y, success);
408 _LETRACE("g#%-4d (%.2f, %.2f)", i, x, y);
409
410 fFontInstance->getGlyphAdvance(glyphStorage[i], advance);
411 x += advance.fX;
412 y += advance.fY;
413
414
415 }
416
417 glyphStorage.setPosition(glyphCount, x, y, success);
418 }
419
adjustGlyphPositions(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,LEGlyphStorage & glyphStorage,LEErrorCode & success)420 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
421 LEGlyphStorage &glyphStorage, LEErrorCode &success)
422 {
423 if (LE_FAILURE(success)) {
424 return;
425 }
426
427 if (chars == NULL || offset < 0 || count < 0) {
428 success = LE_ILLEGAL_ARGUMENT_ERROR;
429 return;
430 }
431
432 LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(LETableReference::kStaticData, (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable,
433 CanonShaping::glyphDefinitionTableLen);
434 CanonMarkFilter filter(gdefTable, success);
435
436 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
437
438 if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */
439 LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success);
440 KernTable kt(kernTable, success);
441 kt.process(glyphStorage, success);
442 }
443
444 // default is no adjustments
445 return;
446 }
447
adjustMarkGlyphs(LEGlyphStorage & glyphStorage,LEGlyphFilter * markFilter,LEErrorCode & success)448 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
449 {
450 float xAdjust = 0;
451 le_int32 p, glyphCount = glyphStorage.getGlyphCount();
452
453 if (LE_FAILURE(success)) {
454 return;
455 }
456
457 if (markFilter == NULL) {
458 success = LE_ILLEGAL_ARGUMENT_ERROR;
459 return;
460 }
461
462 float ignore, prev;
463
464 glyphStorage.getGlyphPosition(0, prev, ignore, success);
465
466 for (p = 0; p < glyphCount; p += 1) {
467 float next, xAdvance;
468
469 glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
470
471 xAdvance = next - prev;
472 _LETRACE("p#%d (%.2f,%.2f)", p, xAdvance, 0);
473 glyphStorage.adjustPosition(p, xAdjust, 0, success);
474
475 if (markFilter->accept(glyphStorage[p], success)) {
476 xAdjust -= xAdvance;
477 }
478
479 prev = next;
480 }
481
482 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
483 }
484
adjustMarkGlyphs(const LEUnicode chars[],le_int32 charCount,le_bool reverse,LEGlyphStorage & glyphStorage,LEGlyphFilter * markFilter,LEErrorCode & success)485 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
486 {
487 float xAdjust = 0;
488 le_int32 c = 0, direction = 1, p;
489 le_int32 glyphCount = glyphStorage.getGlyphCount();
490
491 if (LE_FAILURE(success)) {
492 return;
493 }
494
495 if (markFilter == NULL) {
496 success = LE_ILLEGAL_ARGUMENT_ERROR;
497 return;
498 }
499
500 if (reverse) {
501 c = glyphCount - 1;
502 direction = -1;
503 }
504
505 float ignore, prev;
506
507 glyphStorage.getGlyphPosition(0, prev, ignore, success);
508
509 for (p = 0; p < charCount; p += 1, c += direction) {
510 float next, xAdvance;
511
512 glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
513
514 xAdvance = next - prev;
515
516 _LETRACE("p#%d (%.2f,%.2f)", p, xAdvance, 0);
517
518
519 glyphStorage.adjustPosition(p, xAdjust, 0, success);
520
521 if (markFilter->accept(chars[c], success)) {
522 xAdjust -= xAdvance;
523 }
524
525 prev = next;
526 }
527
528 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
529 }
530
getFontTable(LETag tableTag,size_t & length) const531 const void *LayoutEngine::getFontTable(LETag tableTag, size_t &length) const
532 {
533 return fFontInstance->getFontTable(tableTag, length);
534 }
535
mapCharsToGlyphs(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,le_bool mirror,LEGlyphStorage & glyphStorage,LEErrorCode & success)536 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
537 LEGlyphStorage &glyphStorage, LEErrorCode &success)
538 {
539 if (LE_FAILURE(success)) {
540 return;
541 }
542
543 glyphStorage.allocateGlyphArray(count, reverse, success);
544
545 DefaultCharMapper charMapper(TRUE, mirror);
546
547 fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, fFilterZeroWidth, glyphStorage);
548 }
549
550 // Input: characters, font?
551 // Output: glyphs, positions, char indices
552 // 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)553 le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
554 float x, float y, LEErrorCode &success)
555 {
556 if (LE_FAILURE(success)) {
557 return 0;
558 }
559
560 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
561 success = LE_ILLEGAL_ARGUMENT_ERROR;
562 return 0;
563 }
564
565 le_int32 glyphCount;
566
567 if (fGlyphStorage->getGlyphCount() > 0) {
568 fGlyphStorage->reset();
569 }
570
571 glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success);
572 positionGlyphs(*fGlyphStorage, x, y, success);
573 adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success);
574
575 return glyphCount;
576 }
577
reset()578 void LayoutEngine::reset()
579 {
580 if(fGlyphStorage!=NULL) {
581 fGlyphStorage->reset();
582 }
583 }
584
layoutEngineFactory(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,LEErrorCode & success)585 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success)
586 {
587 //kerning and ligatures - by default
588 return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, LE_DEFAULT_FEATURE_FLAG, success);
589 }
590
layoutEngineFactory(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags,LEErrorCode & success)591 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
592 {
593 static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
594 static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
595 static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG;
596
597 if (LE_FAILURE(success)) {
598 return NULL;
599 }
600
601 LEReferenceTo<GlyphSubstitutionTableHeader> gsubTable(fontInstance,gsubTableTag,success);
602 LayoutEngine *result = NULL;
603 LETag scriptTag = 0x00000000;
604 LETag languageTag = 0x00000000;
605 LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode);
606
607 // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are
608 // properly tested.
609
610 if ( v2ScriptTag == dev2ScriptTag && gsubTable.isValid() && gsubTable->coversScript(gsubTable, v2ScriptTag, success )) {
611 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success);
612 }
613 else if (gsubTable.isValid() && gsubTable->coversScript(gsubTable, scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode), success)) {
614 switch (scriptCode) {
615 case bengScriptCode:
616 case devaScriptCode:
617 case gujrScriptCode:
618 case kndaScriptCode:
619 case mlymScriptCode:
620 case oryaScriptCode:
621 case guruScriptCode:
622 case tamlScriptCode:
623 case teluScriptCode:
624 case sinhScriptCode:
625 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success);
626 break;
627
628 case arabScriptCode:
629 result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
630 break;
631
632 case hebrScriptCode:
633 // Disable hebrew ligatures since they have only archaic uses, see ticket #8318
634 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success);
635 break;
636
637 case hangScriptCode:
638 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
639 break;
640
641 case haniScriptCode:
642 languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
643
644 switch (languageCode) {
645 case korLanguageCode:
646 case janLanguageCode:
647 case zhtLanguageCode:
648 case zhsLanguageCode:
649 if (gsubTable->coversScriptAndLanguage(gsubTable, scriptTag, languageTag, success, TRUE)) {
650 result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
651 break;
652 }
653
654 // note: falling through to default case.
655 default:
656 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
657 break;
658 }
659
660 break;
661
662 case tibtScriptCode:
663 result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
664 break;
665
666 case khmrScriptCode:
667 result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
668 break;
669
670 default:
671 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
672 break;
673 }
674 } else {
675 LEReferenceTo<MorphTableHeader2> morxTable(fontInstance, morxTableTag, success);
676 if (LE_SUCCESS(success) &&
677 morxTable.isValid() &&
678 SWAPL(morxTable->version)==0x00020000) {
679 result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success);
680 } else {
681 LEReferenceTo<MorphTableHeader> mortTable(fontInstance, mortTableTag, success);
682 if (LE_SUCCESS(success) && mortTable.isValid() && SWAPL(mortTable->version)==0x00010000) { // mort
683 result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success);
684 } else {
685 switch (scriptCode) {
686 case bengScriptCode:
687 case devaScriptCode:
688 case gujrScriptCode:
689 case kndaScriptCode:
690 case mlymScriptCode:
691 case oryaScriptCode:
692 case guruScriptCode:
693 case tamlScriptCode:
694 case teluScriptCode:
695 case sinhScriptCode:
696 {
697 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
698 break;
699 }
700
701 case arabScriptCode:
702 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
703 break;
704
705 //case hebrScriptCode:
706 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
707
708 case thaiScriptCode:
709 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
710 break;
711
712 case hangScriptCode:
713 result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
714 break;
715
716 default:
717 result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
718 break;
719 }
720 }
721 }
722 }
723
724 if (result && LE_FAILURE(success)) {
725 delete result;
726 result = NULL;
727 }
728
729 if (result == NULL) {
730 success = LE_MEMORY_ALLOCATION_ERROR;
731 }
732
733 return result;
734 }
735
~LayoutEngine()736 LayoutEngine::~LayoutEngine() {
737 delete fGlyphStorage;
738 }
739
740 U_NAMESPACE_END
741