• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  *
4  * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved
5  *
6  */
7 
8 #include "LETypes.h"
9 #include "LEScripts.h"
10 #include "LELanguages.h"
11 
12 #include "LayoutEngine.h"
13 #include "CanonShaping.h"
14 #include "OpenTypeLayoutEngine.h"
15 #include "ScriptAndLanguageTags.h"
16 #include "CharSubstitutionFilter.h"
17 
18 #include "GlyphSubstitutionTables.h"
19 #include "GlyphDefinitionTables.h"
20 #include "GlyphPositioningTables.h"
21 
22 #include "LEGlyphStorage.h"
23 #include "GlyphPositionAdjustments.h"
24 
25 #include "GDEFMarkFilter.h"
26 
27 #include "KernTable.h"
28 
29 U_NAMESPACE_BEGIN
30 
31 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine)
32 
33 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
34 #define ligaFeatureTag LE_LIGA_FEATURE_TAG
35 #define cligFeatureTag LE_CLIG_FEATURE_TAG
36 #define kernFeatureTag LE_KERN_FEATURE_TAG
37 #define markFeatureTag LE_MARK_FEATURE_TAG
38 #define mkmkFeatureTag LE_MKMK_FEATURE_TAG
39 #define loclFeatureTag LE_LOCL_FEATURE_TAG
40 #define caltFeatureTag LE_CALT_FEATURE_TAG
41 
42 #define dligFeatureTag LE_DLIG_FEATURE_TAG
43 #define rligFeatureTag LE_RLIG_FEATURE_TAG
44 #define paltFeatureTag LE_PALT_FEATURE_TAG
45 
46 #define hligFeatureTag LE_HLIG_FEATURE_TAG
47 #define smcpFeatureTag LE_SMCP_FEATURE_TAG
48 #define fracFeatureTag LE_FRAC_FEATURE_TAG
49 #define afrcFeatureTag LE_AFRC_FEATURE_TAG
50 #define zeroFeatureTag LE_ZERO_FEATURE_TAG
51 #define swshFeatureTag LE_SWSH_FEATURE_TAG
52 #define cswhFeatureTag LE_CSWH_FEATURE_TAG
53 #define saltFeatureTag LE_SALT_FEATURE_TAG
54 #define naltFeatureTag LE_NALT_FEATURE_TAG
55 #define rubyFeatureTag LE_RUBY_FEATURE_TAG
56 #define ss01FeatureTag LE_SS01_FEATURE_TAG
57 #define ss02FeatureTag LE_SS02_FEATURE_TAG
58 #define ss03FeatureTag LE_SS03_FEATURE_TAG
59 #define ss04FeatureTag LE_SS04_FEATURE_TAG
60 #define ss05FeatureTag LE_SS05_FEATURE_TAG
61 #define ss06FeatureTag LE_SS06_FEATURE_TAG
62 #define ss07FeatureTag LE_SS07_FEATURE_TAG
63 
64 #define ccmpFeatureMask 0x80000000UL
65 #define ligaFeatureMask 0x40000000UL
66 #define cligFeatureMask 0x20000000UL
67 #define kernFeatureMask 0x10000000UL
68 #define paltFeatureMask 0x08000000UL
69 #define markFeatureMask 0x04000000UL
70 #define mkmkFeatureMask 0x02000000UL
71 #define loclFeatureMask 0x01000000UL
72 #define caltFeatureMask 0x00800000UL
73 
74 #define dligFeatureMask 0x00400000UL
75 #define rligFeatureMask 0x00200000UL
76 #define hligFeatureMask 0x00100000UL
77 #define smcpFeatureMask 0x00080000UL
78 #define fracFeatureMask 0x00040000UL
79 #define afrcFeatureMask 0x00020000UL
80 #define zeroFeatureMask 0x00010000UL
81 #define swshFeatureMask 0x00008000UL
82 #define cswhFeatureMask 0x00004000UL
83 #define saltFeatureMask 0x00002000UL
84 #define naltFeatureMask 0x00001000UL
85 #define rubyFeatureMask 0x00000800UL
86 #define ss01FeatureMask 0x00000400UL
87 #define ss02FeatureMask 0x00000200UL
88 #define ss03FeatureMask 0x00000100UL
89 #define ss04FeatureMask 0x00000080UL
90 #define ss05FeatureMask 0x00000040UL
91 #define ss06FeatureMask 0x00000020UL
92 #define ss07FeatureMask 0x00000010UL
93 
94 #define minimalFeatures     (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask | loclFeatureMask | caltFeatureMask)
95 
96 static const FeatureMap featureMap[] =
97 {
98     {ccmpFeatureTag, ccmpFeatureMask},
99     {ligaFeatureTag, ligaFeatureMask},
100     {cligFeatureTag, cligFeatureMask},
101     {kernFeatureTag, kernFeatureMask},
102     {paltFeatureTag, paltFeatureMask},
103     {markFeatureTag, markFeatureMask},
104     {mkmkFeatureTag, mkmkFeatureMask},
105     {loclFeatureTag, loclFeatureMask},
106     {caltFeatureTag, caltFeatureMask},
107     {hligFeatureTag, hligFeatureMask},
108     {smcpFeatureTag, smcpFeatureMask},
109     {fracFeatureTag, fracFeatureMask},
110     {afrcFeatureTag, afrcFeatureMask},
111     {zeroFeatureTag, zeroFeatureMask},
112     {swshFeatureTag, swshFeatureMask},
113     {cswhFeatureTag, cswhFeatureMask},
114     {saltFeatureTag, saltFeatureMask},
115     {naltFeatureTag, naltFeatureMask},
116     {rubyFeatureTag, rubyFeatureMask},
117     {ss01FeatureTag, ss01FeatureMask},
118     {ss02FeatureTag, ss02FeatureMask},
119     {ss03FeatureTag, ss03FeatureMask},
120     {ss04FeatureTag, ss04FeatureMask},
121     {ss05FeatureTag, ss05FeatureMask},
122     {ss06FeatureTag, ss06FeatureMask},
123     {ss07FeatureTag, ss07FeatureMask}
124 };
125 
126 static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap);
127 
OpenTypeLayoutEngine(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags,const GlyphSubstitutionTableHeader * gsubTable,LEErrorCode & success)128 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
129                         le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
130     : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureMask(minimalFeatures),
131       fFeatureMap(featureMap), fFeatureMapCount(featureMapCount), fFeatureOrder(FALSE),
132       fGSUBTable(gsubTable), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL)
133 {
134     static const le_uint32 gdefTableTag = LE_GDEF_TABLE_TAG;
135     static const le_uint32 gposTableTag = LE_GPOS_TABLE_TAG;
136     const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag);
137 
138     switch (typoFlags & (LE_SS01_FEATURE_FLAG
139                          | LE_SS02_FEATURE_FLAG
140                          | LE_SS03_FEATURE_FLAG
141                          | LE_SS04_FEATURE_FLAG
142                          | LE_SS05_FEATURE_FLAG
143                          | LE_SS06_FEATURE_FLAG
144                          | LE_SS07_FEATURE_FLAG)) {
145         case LE_SS01_FEATURE_FLAG:
146             fFeatureMask |= ss01FeatureMask;
147             break;
148         case LE_SS02_FEATURE_FLAG:
149             fFeatureMask |= ss02FeatureMask;
150             break;
151         case LE_SS03_FEATURE_FLAG:
152             fFeatureMask |= ss03FeatureMask;
153             break;
154         case LE_SS04_FEATURE_FLAG:
155             fFeatureMask |= ss04FeatureMask;
156             break;
157         case LE_SS05_FEATURE_FLAG:
158             fFeatureMask |= ss05FeatureMask;
159             break;
160         case LE_SS06_FEATURE_FLAG:
161             fFeatureMask |= ss06FeatureMask;
162             break;
163         case LE_SS07_FEATURE_FLAG:
164             fFeatureMask |= ss07FeatureMask;
165             break;
166     }
167 
168     if (typoFlags & LE_Kerning_FEATURE_FLAG) {
169       fFeatureMask |= (kernFeatureMask | paltFeatureMask);
170       // Convenience.
171     }
172     if (typoFlags & LE_Ligatures_FEATURE_FLAG) {
173       fFeatureMask |= (ligaFeatureMask | cligFeatureMask);
174       // Convenience TODO: should add: .. dligFeatureMask | rligFeatureMask ?
175     }
176     if (typoFlags & LE_CLIG_FEATURE_FLAG) fFeatureMask |= cligFeatureMask;
177     if (typoFlags & LE_DLIG_FEATURE_FLAG) fFeatureMask |= dligFeatureMask;
178     if (typoFlags & LE_HLIG_FEATURE_FLAG) fFeatureMask |= hligFeatureMask;
179     if (typoFlags & LE_LIGA_FEATURE_FLAG) fFeatureMask |= ligaFeatureMask;
180     if (typoFlags & LE_RLIG_FEATURE_FLAG) fFeatureMask |= rligFeatureMask;
181     if (typoFlags & LE_SMCP_FEATURE_FLAG) fFeatureMask |= smcpFeatureMask;
182     if (typoFlags & LE_FRAC_FEATURE_FLAG) fFeatureMask |= fracFeatureMask;
183     if (typoFlags & LE_AFRC_FEATURE_FLAG) fFeatureMask |= afrcFeatureMask;
184     if (typoFlags & LE_ZERO_FEATURE_FLAG) fFeatureMask |= zeroFeatureMask;
185     if (typoFlags & LE_SWSH_FEATURE_FLAG) fFeatureMask |= swshFeatureMask;
186     if (typoFlags & LE_CSWH_FEATURE_FLAG) fFeatureMask |= cswhFeatureMask;
187     if (typoFlags & LE_SALT_FEATURE_FLAG) fFeatureMask |= saltFeatureMask;
188     if (typoFlags & LE_RUBY_FEATURE_FLAG) fFeatureMask |= rubyFeatureMask;
189     if (typoFlags & LE_NALT_FEATURE_FLAG) {
190       // Mutually exclusive with ALL other features. http://www.microsoft.com/typography/otspec/features_ko.htm
191       fFeatureMask = naltFeatureMask;
192     }
193 
194     if (typoFlags & LE_CHAR_FILTER_FEATURE_FLAG) {
195       // This isn't a font feature, but requests a Char Substitution Filter
196       fSubstitutionFilter = new CharSubstitutionFilter(fontInstance);
197     }
198 
199     setScriptAndLanguageTags();
200 
201     fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag);
202 
203 // JK patch, 2008-05-30 - see Sinhala bug report and LKLUG font
204 //    if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) {
205     if (gposTable != NULL && gposTable->coversScript(fScriptTag)) {
206         fGPOSTable = gposTable;
207     }
208 }
209 
reset()210 void OpenTypeLayoutEngine::reset()
211 {
212     // NOTE: if we're called from
213     // the destructor, LayoutEngine;:reset()
214     // will have been called already by
215     // LayoutEngine::~LayoutEngine()
216     LayoutEngine::reset();
217 }
218 
OpenTypeLayoutEngine(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags,LEErrorCode & success)219 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
220                        le_int32 typoFlags, LEErrorCode &success)
221     : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureOrder(FALSE),
222       fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL)
223 {
224     setScriptAndLanguageTags();
225 }
226 
~OpenTypeLayoutEngine()227 OpenTypeLayoutEngine::~OpenTypeLayoutEngine()
228 {
229     if (fTypoFlags & 0x80000000L) {
230         delete fSubstitutionFilter;
231     }
232 
233     reset();
234 }
235 
getScriptTag(le_int32 scriptCode)236 LETag OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode)
237 {
238     if (scriptCode < 0 || scriptCode >= scriptCodeCount) {
239         return 0xFFFFFFFF;
240     }
241     return scriptTags[scriptCode];
242 }
243 
getV2ScriptTag(le_int32 scriptCode)244 LETag OpenTypeLayoutEngine::getV2ScriptTag(le_int32 scriptCode)
245 {
246 	switch (scriptCode) {
247 		case bengScriptCode :    return bng2ScriptTag;
248 		case devaScriptCode :    return dev2ScriptTag;
249 		case gujrScriptCode :    return gjr2ScriptTag;
250 		case guruScriptCode :    return gur2ScriptTag;
251 		case kndaScriptCode :    return knd2ScriptTag;
252 		case mlymScriptCode :    return mlm2ScriptTag;
253 		case oryaScriptCode :    return ory2ScriptTag;
254 		case tamlScriptCode :    return tml2ScriptTag;
255 		case teluScriptCode :    return tel2ScriptTag;
256 		default:                 return nullScriptTag;
257 	}
258 }
259 
getLangSysTag(le_int32 languageCode)260 LETag OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode)
261 {
262     if (languageCode < 0 || languageCode >= languageCodeCount) {
263         return 0xFFFFFFFF;
264     }
265 
266     return languageTags[languageCode];
267 }
268 
setScriptAndLanguageTags()269 void OpenTypeLayoutEngine::setScriptAndLanguageTags()
270 {
271     fScriptTag  = getScriptTag(fScriptCode);
272     fScriptTagV2 = getV2ScriptTag(fScriptCode);
273     fLangSysTag = getLangSysTag(fLanguageCode);
274 }
275 
characterProcessing(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEUnicode * & outChars,LEGlyphStorage & glyphStorage,LEErrorCode & success)276 le_int32 OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
277                 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
278 {
279     if (LE_FAILURE(success)) {
280         return 0;
281     }
282 
283     if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
284         success = LE_ILLEGAL_ARGUMENT_ERROR;
285         return 0;
286     }
287 
288     // This is the cheapest way to get mark reordering only for Hebrew.
289     // We could just do the mark reordering for all scripts, but most
290     // of them probably don't need it... Another option would be to
291     // add a HebrewOpenTypeLayoutEngine subclass, but the only thing it
292     // would need to do is mark reordering, so that seems like overkill.
293     if (fScriptCode == hebrScriptCode) {
294         outChars = LE_NEW_ARRAY(LEUnicode, count);
295 
296         if (outChars == NULL) {
297             success = LE_MEMORY_ALLOCATION_ERROR;
298             return 0;
299         }
300 
301         if (LE_FAILURE(success)) {
302             LE_DELETE_ARRAY(outChars);
303             return 0;
304         }
305 
306         CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage);
307     }
308 
309     if (LE_FAILURE(success)) {
310         return 0;
311     }
312 
313     glyphStorage.allocateGlyphArray(count, rightToLeft, success);
314     glyphStorage.allocateAuxData(success);
315 
316     for (le_int32 i = 0; i < count; i += 1) {
317         glyphStorage.setAuxData(i, fFeatureMask, success);
318     }
319 
320     return count;
321 }
322 
323 // Input: characters, tags
324 // Output: glyphs, char indices
glyphProcessing(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEGlyphStorage & glyphStorage,LEErrorCode & success)325 le_int32 OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
326                                                LEGlyphStorage &glyphStorage, LEErrorCode &success)
327 {
328     if (LE_FAILURE(success)) {
329         return 0;
330     }
331 
332     if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
333         success = LE_ILLEGAL_ARGUMENT_ERROR;
334         return 0;
335     }
336 
337     mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
338 
339     if (LE_FAILURE(success)) {
340         return 0;
341     }
342 
343     if (fGSUBTable != NULL) {
344         if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) {
345             count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter,
346                                     fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
347 
348         } else {
349         count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter,
350                                     fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
351         }
352     }
353 
354     return count;
355 }
356 // Input: characters, tags
357 // Output: glyphs, char indices
glyphSubstitution(le_int32 count,le_int32 max,le_bool rightToLeft,LEGlyphStorage & glyphStorage,LEErrorCode & success)358 le_int32 OpenTypeLayoutEngine::glyphSubstitution(le_int32 count, le_int32 max, le_bool rightToLeft,
359                                                LEGlyphStorage &glyphStorage, LEErrorCode &success)
360 {
361     if (LE_FAILURE(success)) {
362         return 0;
363     }
364 
365     if ( count < 0 || max < 0 ) {
366         success = LE_ILLEGAL_ARGUMENT_ERROR;
367         return 0;
368     }
369 
370     if (fGSUBTable != NULL) {
371         if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) {
372             count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter,
373                                     fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
374 
375         } else {
376         count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter,
377                                     fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
378         }
379     }
380 
381     return count;
382 }
glyphPostProcessing(LEGlyphStorage & tempGlyphStorage,LEGlyphStorage & glyphStorage,LEErrorCode & success)383 le_int32 OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success)
384 {
385     if (LE_FAILURE(success)) {
386         return 0;
387     }
388 
389     glyphStorage.adoptGlyphArray(tempGlyphStorage);
390     glyphStorage.adoptCharIndicesArray(tempGlyphStorage);
391     glyphStorage.adoptAuxDataArray(tempGlyphStorage);
392     glyphStorage.adoptGlyphCount(tempGlyphStorage);
393 
394     return glyphStorage.getGlyphCount();
395 }
396 
computeGlyphs(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEGlyphStorage & glyphStorage,LEErrorCode & success)397 le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success)
398 {
399     LEUnicode *outChars = NULL;
400     LEGlyphStorage fakeGlyphStorage;
401     le_int32 outCharCount, outGlyphCount;
402 
403     if (LE_FAILURE(success)) {
404         return 0;
405     }
406 
407     if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
408         success = LE_ILLEGAL_ARGUMENT_ERROR;
409         return 0;
410     }
411 
412     outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, fakeGlyphStorage, success);
413 
414     if (LE_FAILURE(success)) {
415         return 0;
416     }
417 
418     if (outChars != NULL) {
419         // le_int32 fakeGlyphCount =
420         glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success);
421         LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
422         //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount);
423     } else {
424         // le_int32 fakeGlyphCount =
425         glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success);
426         //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount);
427     }
428 
429     if (LE_FAILURE(success)) {
430         return 0;
431     }
432 
433     outGlyphCount = glyphPostProcessing(fakeGlyphStorage, glyphStorage, success);
434 
435     return outGlyphCount;
436 }
437 
438 // apply GPOS table, if any
adjustGlyphPositions(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,LEGlyphStorage & glyphStorage,LEErrorCode & success)439 void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
440                                                 LEGlyphStorage &glyphStorage, LEErrorCode &success)
441 {
442     if (LE_FAILURE(success)) {
443         return;
444     }
445 
446     if (chars == NULL || offset < 0 || count < 0) {
447         success = LE_ILLEGAL_ARGUMENT_ERROR;
448         return;
449     }
450 
451     le_int32 glyphCount = glyphStorage.getGlyphCount();
452     if (glyphCount == 0) {
453         return;
454     }
455 
456     if (fGPOSTable != NULL) {
457         GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount);
458         le_int32 i;
459 
460         if (adjustments == NULL) {
461             success = LE_MEMORY_ALLOCATION_ERROR;
462             return;
463         }
464 
465 #if 0
466         // Don't need to do this if we allocate
467         // the adjustments array w/ new...
468         for (i = 0; i < glyphCount; i += 1) {
469             adjustments->setXPlacement(i, 0);
470             adjustments->setYPlacement(i, 0);
471 
472             adjustments->setXAdvance(i, 0);
473             adjustments->setYAdvance(i, 0);
474 
475             adjustments->setBaseOffset(i, -1);
476         }
477 #endif
478 
479         if (fGPOSTable != NULL) {
480             if (fScriptTagV2 != nullScriptTag && fGPOSTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) {
481                 fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, fGDEFTable, success, fFontInstance,
482                                 fFeatureMap, fFeatureMapCount, fFeatureOrder);
483 
484             } else {
485                 fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, success, fFontInstance,
486                                 fFeatureMap, fFeatureMapCount, fFeatureOrder);
487             }
488         } else if ( fTypoFlags & 0x1 ) {
489             static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG;
490             KernTable kt(fFontInstance, getFontTable(kernTableTag));
491             kt.process(glyphStorage);
492         }
493 
494         float xAdjust = 0, yAdjust = 0;
495 
496         for (i = 0; i < glyphCount; i += 1) {
497             float xAdvance   = adjustments->getXAdvance(i);
498             float yAdvance   = adjustments->getYAdvance(i);
499             float xPlacement = 0;
500             float yPlacement = 0;
501 
502 
503 #if 0
504             // This is where separate kerning adjustments
505             // should get applied.
506             xAdjust += xKerning;
507             yAdjust += yKerning;
508 #endif
509 
510             for (le_int32 base = i; base >= 0; base = adjustments->getBaseOffset(base)) {
511                 xPlacement += adjustments->getXPlacement(base);
512                 yPlacement += adjustments->getYPlacement(base);
513             }
514 
515             xPlacement = fFontInstance->xUnitsToPoints(xPlacement);
516             yPlacement = fFontInstance->yUnitsToPoints(yPlacement);
517             glyphStorage.adjustPosition(i, xAdjust + xPlacement, -(yAdjust + yPlacement), success);
518 
519             xAdjust += fFontInstance->xUnitsToPoints(xAdvance);
520             yAdjust += fFontInstance->yUnitsToPoints(yAdvance);
521         }
522 
523         glyphStorage.adjustPosition(glyphCount, xAdjust, -yAdjust, success);
524 
525         delete adjustments;
526     } else {
527         // if there was no GPOS table, maybe there's non-OpenType kerning we can use
528         //   Google Patch: disable this.  Causes problems with Tamil.
529         //       Umesh says layout is poor both with and without the change, but
530         //       worse with the change.  See ocean/imageprocessing/layout_test_unittest.cc
531         //   Public ICU ticket for this problem is  #7742
532         // LayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success);
533     }
534 
535     LEGlyphID zwnj  = fFontInstance->mapCharToGlyph(0x200C);
536 
537     if (zwnj != 0x0000) {
538         for (le_int32 g = 0; g < glyphCount; g += 1) {
539             LEGlyphID glyph = glyphStorage[g];
540 
541             if (glyph == zwnj) {
542                 glyphStorage[g] = LE_SET_GLYPH(glyph, 0xFFFF);
543             }
544         }
545     }
546 
547 #if 0
548     // Don't know why this is here...
549     LE_DELETE_ARRAY(fFeatureTags);
550     fFeatureTags = NULL;
551 #endif
552 }
553 
554 U_NAMESPACE_END
555