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