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