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