• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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