1
2 /*
3 *
4 * (C) Copyright IBM Corp. 1998-2007 - 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 "OpenTypeLayoutEngine.h"
14 #include "ScriptAndLanguageTags.h"
15 #include "CharSubstitutionFilter.h"
16
17 #include "GlyphSubstitutionTables.h"
18 #include "GlyphDefinitionTables.h"
19 #include "GlyphPositioningTables.h"
20
21 #include "LEGlyphStorage.h"
22 #include "GlyphPositionAdjustments.h"
23
24 #include "GDEFMarkFilter.h"
25
26 U_NAMESPACE_BEGIN
27
28 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine)
29
30 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
31 #define ligaFeatureTag LE_LIGA_FEATURE_TAG
32 #define cligFeatureTag LE_CLIG_FEATURE_TAG
33 #define kernFeatureTag LE_KERN_FEATURE_TAG
34 #define markFeatureTag LE_MARK_FEATURE_TAG
35 #define mkmkFeatureTag LE_MKMK_FEATURE_TAG
36
37 // 'dlig' not used at the moment
38 #define dligFeatureTag 0x646C6967
39
40 // 'palt'
41 #define paltFeatureTag 0x70616C74
42
43 #define ccmpFeatureMask 0x80000000UL
44 #define ligaFeatureMask 0x40000000UL
45 #define cligFeatureMask 0x20000000UL
46 #define kernFeatureMask 0x10000000UL
47 #define paltFeatureMask 0x08000000UL
48 #define markFeatureMask 0x04000000UL
49 #define mkmkFeatureMask 0x02000000UL
50
51 #define minimalFeatures (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask)
52 #define ligaFeatures (ligaFeatureMask | cligFeatureMask | minimalFeatures)
53 #define kernFeatures (kernFeatureMask | paltFeatureMask | minimalFeatures)
54 #define kernAndLigaFeatures (ligaFeatures | kernFeatures)
55
56 static const FeatureMap featureMap[] =
57 {
58 {ccmpFeatureTag, ccmpFeatureMask},
59 {ligaFeatureTag, ligaFeatureMask},
60 {cligFeatureTag, cligFeatureMask},
61 {kernFeatureTag, kernFeatureMask},
62 {paltFeatureTag, paltFeatureMask},
63 {markFeatureTag, markFeatureMask},
64 {mkmkFeatureTag, mkmkFeatureMask}
65 };
66
67 static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap);
68
OpenTypeLayoutEngine(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags,const GlyphSubstitutionTableHeader * gsubTable)69 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
70 le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable)
71 : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags), fFeatureMask(minimalFeatures),
72 fFeatureMap(featureMap), fFeatureMapCount(featureMapCount), fFeatureOrder(FALSE),
73 fGSUBTable(gsubTable), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL)
74 {
75 static const le_uint32 gdefTableTag = LE_GDEF_TABLE_TAG;
76 static const le_uint32 gposTableTag = LE_GPOS_TABLE_TAG;
77 const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag);
78
79 // todo: switch to more flags and bitfield rather than list of feature tags?
80 switch (typoFlags & ~0x80000000L) {
81 case 0: break; // default
82 case 1: fFeatureMask = kernFeatures; break;
83 case 2: fFeatureMask = ligaFeatures; break;
84 case 3: fFeatureMask = kernAndLigaFeatures; break;
85 default: break;
86 }
87
88 if (typoFlags & 0x80000000L) {
89 fSubstitutionFilter = new CharSubstitutionFilter(fontInstance);
90 }
91
92 setScriptAndLanguageTags();
93
94 fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag);
95
96 if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) {
97 fGPOSTable = gposTable;
98 }
99 }
100
reset()101 void OpenTypeLayoutEngine::reset()
102 {
103 // NOTE: if we're called from
104 // the destructor, LayoutEngine;:reset()
105 // will have been called already by
106 // LayoutEngine::~LayoutEngine()
107 LayoutEngine::reset();
108 }
109
OpenTypeLayoutEngine(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags)110 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
111 le_int32 typoFlags)
112 : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags), fFeatureOrder(FALSE),
113 fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL)
114 {
115 setScriptAndLanguageTags();
116 }
117
~OpenTypeLayoutEngine()118 OpenTypeLayoutEngine::~OpenTypeLayoutEngine()
119 {
120 if (fTypoFlags & 0x80000000L) {
121 delete fSubstitutionFilter;
122 }
123
124 reset();
125 }
126
getScriptTag(le_int32 scriptCode)127 LETag OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode)
128 {
129 if (scriptCode < 0 || scriptCode >= scriptCodeCount) {
130 return 0xFFFFFFFF;
131 }
132
133 return scriptTags[scriptCode];
134 }
135
getLangSysTag(le_int32 languageCode)136 LETag OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode)
137 {
138 if (languageCode < 0 || languageCode >= languageCodeCount) {
139 return 0xFFFFFFFF;
140 }
141
142 return languageTags[languageCode];
143 }
144
setScriptAndLanguageTags()145 void OpenTypeLayoutEngine::setScriptAndLanguageTags()
146 {
147 fScriptTag = getScriptTag(fScriptCode);
148 fLangSysTag = getLangSysTag(fLanguageCode);
149 }
150
characterProcessing(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEUnicode * & outChars,LEGlyphStorage & glyphStorage,LEErrorCode & success)151 le_int32 OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
152 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
153 {
154 if (LE_FAILURE(success)) {
155 return 0;
156 }
157
158 if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
159 success = LE_ILLEGAL_ARGUMENT_ERROR;
160 return 0;
161 }
162
163 le_int32 outCharCount = LayoutEngine::characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success);
164
165 if (LE_FAILURE(success)) {
166 return 0;
167 }
168
169 glyphStorage.allocateGlyphArray(outCharCount, rightToLeft, success);
170 glyphStorage.allocateAuxData(success);
171
172 for (le_int32 i = 0; i < outCharCount; i += 1) {
173 glyphStorage.setAuxData(i, fFeatureMask, success);
174 }
175
176 return outCharCount;
177 }
178
179 // Input: characters, tags
180 // Output: glyphs, char indices
glyphProcessing(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEGlyphStorage & glyphStorage,LEErrorCode & success)181 le_int32 OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
182 LEGlyphStorage &glyphStorage, LEErrorCode &success)
183 {
184 if (LE_FAILURE(success)) {
185 return 0;
186 }
187
188 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
189 success = LE_ILLEGAL_ARGUMENT_ERROR;
190 return 0;
191 }
192
193 mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
194
195 if (LE_FAILURE(success)) {
196 return 0;
197 }
198
199 if (fGSUBTable != NULL) {
200 count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter,
201 fFeatureMap, fFeatureMapCount, fFeatureOrder);
202 }
203
204 return count;
205 }
206
glyphPostProcessing(LEGlyphStorage & tempGlyphStorage,LEGlyphStorage & glyphStorage,LEErrorCode & success)207 le_int32 OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success)
208 {
209 if (LE_FAILURE(success)) {
210 return 0;
211 }
212
213 glyphStorage.adoptGlyphArray(tempGlyphStorage);
214 glyphStorage.adoptCharIndicesArray(tempGlyphStorage);
215 glyphStorage.adoptAuxDataArray(tempGlyphStorage);
216 glyphStorage.adoptGlyphCount(tempGlyphStorage);
217
218 return glyphStorage.getGlyphCount();
219 }
220
computeGlyphs(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEGlyphStorage & glyphStorage,LEErrorCode & success)221 le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success)
222 {
223 LEUnicode *outChars = NULL;
224 LEGlyphStorage fakeGlyphStorage;
225 le_int32 outCharCount, outGlyphCount, fakeGlyphCount;
226
227 if (LE_FAILURE(success)) {
228 return 0;
229 }
230
231 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
232 success = LE_ILLEGAL_ARGUMENT_ERROR;
233 return 0;
234 }
235
236 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, fakeGlyphStorage, success);
237
238 if (LE_FAILURE(success)) {
239 return 0;
240 }
241
242 if (outChars != NULL) {
243 fakeGlyphCount = glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success);
244 LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
245 //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount);
246 } else {
247 fakeGlyphCount = glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success);
248 //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount);
249 }
250
251 if (LE_FAILURE(success)) {
252 return 0;
253 }
254
255 outGlyphCount = glyphPostProcessing(fakeGlyphStorage, glyphStorage, success);
256
257 return outGlyphCount;
258 }
259
260 // apply GPOS table, if any
adjustGlyphPositions(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,LEGlyphStorage & glyphStorage,LEErrorCode & success)261 void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
262 LEGlyphStorage &glyphStorage, LEErrorCode &success)
263 {
264 if (LE_FAILURE(success)) {
265 return;
266 }
267
268 if (chars == NULL || offset < 0 || count < 0) {
269 success = LE_ILLEGAL_ARGUMENT_ERROR;
270 return;
271 }
272
273 le_int32 glyphCount = glyphStorage.getGlyphCount();
274
275 if (glyphCount > 0 && fGPOSTable != NULL) {
276 GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount);
277 le_int32 i;
278
279 if (adjustments == NULL) {
280 success = LE_MEMORY_ALLOCATION_ERROR;
281 return;
282 }
283
284 #if 0
285 // Don't need to do this if we allocate
286 // the adjustments array w/ new...
287 for (i = 0; i < glyphCount; i += 1) {
288 adjustments->setXPlacement(i, 0);
289 adjustments->setYPlacement(i, 0);
290
291 adjustments->setXAdvance(i, 0);
292 adjustments->setYAdvance(i, 0);
293
294 adjustments->setBaseOffset(i, -1);
295 }
296 #endif
297
298 fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, fFontInstance,
299 fFeatureMap, fFeatureMapCount, fFeatureOrder);
300
301 float xAdjust = 0, yAdjust = 0;
302
303 for (i = 0; i < glyphCount; i += 1) {
304 float xAdvance = adjustments->getXAdvance(i);
305 float yAdvance = adjustments->getYAdvance(i);
306 float xPlacement = 0;
307 float yPlacement = 0;
308
309
310 #if 0
311 // This is where separate kerning adjustments
312 // should get applied.
313 xAdjust += xKerning;
314 yAdjust += yKerning;
315 #endif
316
317 for (le_int32 base = i; base >= 0; base = adjustments->getBaseOffset(base)) {
318 xPlacement += adjustments->getXPlacement(base);
319 yPlacement += adjustments->getYPlacement(base);
320 }
321
322 xPlacement = fFontInstance->xUnitsToPoints(xPlacement);
323 yPlacement = fFontInstance->yUnitsToPoints(yPlacement);
324 glyphStorage.adjustPosition(i, xAdjust + xPlacement, -(yAdjust + yPlacement), success);
325
326 xAdjust += fFontInstance->xUnitsToPoints(xAdvance);
327 yAdjust += fFontInstance->yUnitsToPoints(yAdvance);
328 }
329
330 glyphStorage.adjustPosition(glyphCount, xAdjust, -yAdjust, success);
331
332 delete adjustments;
333 }
334
335 LEGlyphID zwnj = fFontInstance->mapCharToGlyph(0x200C);
336 #if 0
337 // The nbsp translation was only here to make one
338 // broken font work. Not a good idea in general...
339 LEGlyphID nbsp = fFontInstance->mapCharToGlyph(0x00A0);
340 LEGlyphID space = fFontInstance->mapCharToGlyph(0x0020);
341 #endif
342
343 if (zwnj != 0x0000) {
344 for (le_int32 g = 0; g < glyphCount; g += 1) {
345 LEGlyphID glyph = glyphStorage[g];
346
347 if (glyph == zwnj) {
348 glyphStorage[g] = LE_SET_GLYPH(glyph, 0xFFFF);
349 #if 0
350 } else if (glyph == nbsp) {
351 glyphStorage[g] = LE_SET_GLYPH(glyph, space);
352 #endif
353 }
354 }
355 }
356
357 #if 0
358 // Don't know why this is here...
359 LE_DELETE_ARRAY(fFeatureTags);
360 fFeatureTags = NULL;
361 #endif
362 }
363
364 U_NAMESPACE_END
365