]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | |
2 | /* | |
b75a7d8f | 3 | * |
374ca955 | 4 | * (C) Copyright IBM Corp. 1998-2004 - 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" | |
13 | #include "OpenTypeLayoutEngine.h" | |
14 | #include "ScriptAndLanguageTags.h" | |
15 | ||
16 | #include "GlyphSubstitutionTables.h" | |
17 | #include "GlyphDefinitionTables.h" | |
18 | #include "GlyphPositioningTables.h" | |
19 | ||
374ca955 A |
20 | #include "LEGlyphStorage.h" |
21 | ||
b75a7d8f A |
22 | #include "GDEFMarkFilter.h" |
23 | ||
24 | U_NAMESPACE_BEGIN | |
25 | ||
374ca955 A |
26 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine) |
27 | ||
28 | static const LETag emptyTag = 0x00000000; | |
29 | ||
30 | static const LETag ccmpFeatureTag = LE_CCMP_FEATURE_TAG; | |
31 | static const LETag ligaFeatureTag = LE_LIGA_FEATURE_TAG; | |
32 | static const LETag cligFeatureTag = LE_CLIG_FEATURE_TAG; | |
33 | static const LETag kernFeatureTag = LE_KERN_FEATURE_TAG; | |
34 | static const LETag markFeatureTag = LE_MARK_FEATURE_TAG; | |
35 | static const LETag mkmkFeatureTag = LE_MKMK_FEATURE_TAG; | |
36 | ||
37 | static const LETag defaultFeatures[] = {ccmpFeatureTag, ligaFeatureTag, cligFeatureTag, kernFeatureTag, markFeatureTag, mkmkFeatureTag, emptyTag}; | |
38 | ||
b75a7d8f A |
39 | |
40 | OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, | |
41 | const GlyphSubstitutionTableHeader *gsubTable) | |
374ca955 A |
42 | : LayoutEngine(fontInstance, scriptCode, languageCode), fFeatureList(defaultFeatures), fFeatureOrder(NULL), |
43 | fGSUBTable(gsubTable), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL) | |
b75a7d8f | 44 | { |
374ca955 A |
45 | static const le_uint32 gdefTableTag = LE_GDEF_TABLE_TAG; |
46 | static const le_uint32 gposTableTag = LE_GPOS_TABLE_TAG; | |
47 | const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag); | |
b75a7d8f A |
48 | |
49 | setScriptAndLanguageTags(); | |
374ca955 A |
50 | |
51 | fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag); | |
52 | ||
53 | if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) { | |
54 | fGPOSTable = gposTable; | |
55 | } | |
b75a7d8f A |
56 | } |
57 | ||
58 | void OpenTypeLayoutEngine::reset() | |
59 | { | |
60 | // NOTE: if we're called from | |
61 | // the destructor, LayoutEngine;:reset() | |
62 | // will have been called already by | |
63 | // LayoutEngine::~LayoutEngine() | |
64 | LayoutEngine::reset(); | |
b75a7d8f A |
65 | } |
66 | ||
67 | OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode) | |
374ca955 | 68 | : LayoutEngine(fontInstance, scriptCode, languageCode), fFeatureOrder(NULL), |
b75a7d8f A |
69 | fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL) |
70 | { | |
71 | setScriptAndLanguageTags(); | |
72 | } | |
73 | ||
74 | OpenTypeLayoutEngine::~OpenTypeLayoutEngine() | |
75 | { | |
76 | reset(); | |
77 | } | |
78 | ||
79 | LETag OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode) | |
80 | { | |
81 | if (scriptCode < 0 || scriptCode >= scriptCodeCount) { | |
82 | return 0xFFFFFFFF; | |
83 | } | |
84 | ||
85 | return scriptTags[scriptCode]; | |
86 | } | |
87 | ||
88 | LETag OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode) | |
89 | { | |
90 | if (languageCode < 0 || languageCode >= languageCodeCount) { | |
91 | return 0xFFFFFFFF; | |
92 | } | |
93 | ||
94 | return languageTags[languageCode]; | |
95 | } | |
96 | ||
97 | void OpenTypeLayoutEngine::setScriptAndLanguageTags() | |
98 | { | |
99 | fScriptTag = getScriptTag(fScriptCode); | |
100 | fLangSysTag = getLangSysTag(fLanguageCode); | |
101 | } | |
102 | ||
374ca955 A |
103 | le_int32 OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, |
104 | LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) | |
105 | { | |
106 | if (LE_FAILURE(success)) { | |
107 | return 0; | |
108 | } | |
109 | ||
110 | if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { | |
111 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
112 | return 0; | |
113 | } | |
114 | ||
115 | le_int32 outCharCount = LayoutEngine::characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success); | |
116 | ||
117 | if (LE_FAILURE(success)) { | |
118 | return 0; | |
119 | } | |
120 | ||
121 | glyphStorage.allocateGlyphArray(outCharCount, rightToLeft, success); | |
122 | glyphStorage.allocateAuxData(success); | |
123 | ||
124 | for (le_int32 i = 0; i < outCharCount; i += 1) { | |
125 | glyphStorage.setAuxData(i, (void *) fFeatureList, success); | |
126 | } | |
127 | ||
128 | return outCharCount; | |
129 | } | |
130 | ||
b75a7d8f A |
131 | // Input: characters, tags |
132 | // Output: glyphs, char indices | |
374ca955 A |
133 | le_int32 OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, |
134 | LEGlyphStorage &glyphStorage, LEErrorCode &success) | |
b75a7d8f A |
135 | { |
136 | if (LE_FAILURE(success)) { | |
137 | return 0; | |
138 | } | |
139 | ||
140 | if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { | |
141 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
142 | return 0; | |
143 | } | |
144 | ||
374ca955 | 145 | mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success); |
b75a7d8f A |
146 | |
147 | if (LE_FAILURE(success)) { | |
148 | return 0; | |
149 | } | |
150 | ||
151 | if (fGSUBTable != NULL) { | |
374ca955 | 152 | count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, fFeatureOrder); |
b75a7d8f A |
153 | } |
154 | ||
155 | return count; | |
156 | } | |
157 | ||
374ca955 A |
158 | le_int32 OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success) |
159 | { | |
160 | if (LE_FAILURE(success)) { | |
161 | return 0; | |
162 | } | |
163 | ||
164 | glyphStorage.adoptGlyphArray(tempGlyphStorage); | |
165 | glyphStorage.adoptCharIndicesArray(tempGlyphStorage); | |
166 | glyphStorage.adoptAuxDataArray(tempGlyphStorage); | |
167 | glyphStorage.adoptGlyphCount(tempGlyphStorage); | |
168 | ||
169 | return glyphStorage.getGlyphCount(); | |
170 | } | |
171 | ||
172 | le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success) | |
b75a7d8f A |
173 | { |
174 | LEUnicode *outChars = NULL; | |
374ca955 | 175 | LEGlyphStorage fakeGlyphStorage; |
b75a7d8f A |
176 | le_int32 outCharCount, outGlyphCount, fakeGlyphCount; |
177 | ||
178 | if (LE_FAILURE(success)) { | |
179 | return 0; | |
180 | } | |
181 | ||
182 | if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { | |
183 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
184 | return 0; | |
185 | } | |
186 | ||
374ca955 | 187 | outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, fakeGlyphStorage, success); |
b75a7d8f A |
188 | |
189 | if (outChars != NULL) { | |
374ca955 A |
190 | fakeGlyphCount = glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success); |
191 | LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... | |
b75a7d8f A |
192 | //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount); |
193 | } else { | |
374ca955 | 194 | fakeGlyphCount = glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success); |
b75a7d8f A |
195 | //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount); |
196 | } | |
197 | ||
374ca955 | 198 | outGlyphCount = glyphPostProcessing(fakeGlyphStorage, glyphStorage, success); |
b75a7d8f A |
199 | |
200 | return outGlyphCount; | |
201 | } | |
202 | ||
203 | // apply GPOS table, if any | |
204 | void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, | |
374ca955 | 205 | LEGlyphStorage &glyphStorage, LEErrorCode &success) |
b75a7d8f A |
206 | { |
207 | if (LE_FAILURE(success)) { | |
208 | return; | |
209 | } | |
210 | ||
374ca955 | 211 | if (chars == NULL || offset < 0 || count < 0) { |
b75a7d8f A |
212 | success = LE_ILLEGAL_ARGUMENT_ERROR; |
213 | return; | |
214 | } | |
215 | ||
374ca955 A |
216 | le_int32 glyphCount = glyphStorage.getGlyphCount(); |
217 | ||
b75a7d8f | 218 | if (glyphCount > 0 && fGPOSTable != NULL) { |
374ca955 | 219 | GlyphPositionAdjustment *adjustments = new GlyphPositionAdjustment[glyphCount]; |
b75a7d8f A |
220 | le_int32 i; |
221 | ||
222 | if (adjustments == NULL) { | |
223 | success = LE_MEMORY_ALLOCATION_ERROR; | |
224 | return; | |
225 | } | |
226 | ||
374ca955 A |
227 | #if 0 |
228 | // Don't need to do this if we allocate | |
229 | // the adjustments array w/ new... | |
b75a7d8f A |
230 | for (i = 0; i < glyphCount; i += 1) { |
231 | adjustments[i].setXPlacement(0); | |
232 | adjustments[i].setYPlacement(0); | |
233 | ||
234 | adjustments[i].setXAdvance(0); | |
235 | adjustments[i].setYAdvance(0); | |
236 | ||
237 | adjustments[i].setBaseOffset(-1); | |
238 | } | |
374ca955 | 239 | #endif |
b75a7d8f | 240 | |
374ca955 | 241 | fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, fFontInstance, fFeatureOrder); |
b75a7d8f A |
242 | |
243 | float xAdjust = 0, yAdjust = 0; | |
244 | ||
245 | for (i = 0; i < glyphCount; i += 1) { | |
246 | float xAdvance = adjustments[i].getXAdvance(); | |
247 | float yAdvance = adjustments[i].getYAdvance(); | |
248 | float xPlacement = 0; | |
249 | float yPlacement = 0; | |
250 | ||
251 | ||
252 | #if 0 | |
253 | // This is where separate kerning adjustments | |
254 | // should get applied. | |
255 | xAdjust += xKerning; | |
256 | yAdjust += yKerning; | |
257 | #endif | |
258 | ||
259 | for (le_int32 base = i; base >= 0; base = adjustments[base].getBaseOffset()) { | |
260 | xPlacement += adjustments[base].getXPlacement(); | |
261 | yPlacement += adjustments[base].getYPlacement(); | |
262 | } | |
263 | ||
374ca955 A |
264 | xPlacement = fFontInstance->xUnitsToPoints(xPlacement); |
265 | yPlacement = fFontInstance->yUnitsToPoints(yPlacement); | |
266 | glyphStorage.adjustPosition(i, xAdjust + xPlacement, -(yAdjust + yPlacement), success); | |
b75a7d8f A |
267 | |
268 | xAdjust += fFontInstance->xUnitsToPoints(xAdvance); | |
269 | yAdjust += fFontInstance->yUnitsToPoints(yAdvance); | |
270 | } | |
271 | ||
374ca955 | 272 | glyphStorage.adjustPosition(glyphCount, xAdjust, -yAdjust, success); |
b75a7d8f | 273 | |
374ca955 | 274 | delete[] adjustments; |
b75a7d8f A |
275 | } |
276 | ||
374ca955 A |
277 | #if 0 |
278 | // Don't know why this is here... | |
b75a7d8f A |
279 | LE_DELETE_ARRAY(fFeatureTags); |
280 | fFeatureTags = NULL; | |
374ca955 | 281 | #endif |
b75a7d8f A |
282 | } |
283 | ||
284 | U_NAMESPACE_END |