]> git.saurik.com Git - apple/icu.git/blame - icuSources/layout/OpenTypeLayoutEngine.cpp
ICU-6.2.22.tar.gz
[apple/icu.git] / icuSources / layout / OpenTypeLayoutEngine.cpp
CommitLineData
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
24U_NAMESPACE_BEGIN
25
374ca955
A
26UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine)
27
28static const LETag emptyTag = 0x00000000;
29
30static const LETag ccmpFeatureTag = LE_CCMP_FEATURE_TAG;
31static const LETag ligaFeatureTag = LE_LIGA_FEATURE_TAG;
32static const LETag cligFeatureTag = LE_CLIG_FEATURE_TAG;
33static const LETag kernFeatureTag = LE_KERN_FEATURE_TAG;
34static const LETag markFeatureTag = LE_MARK_FEATURE_TAG;
35static const LETag mkmkFeatureTag = LE_MKMK_FEATURE_TAG;
36
37static const LETag defaultFeatures[] = {ccmpFeatureTag, ligaFeatureTag, cligFeatureTag, kernFeatureTag, markFeatureTag, mkmkFeatureTag, emptyTag};
38
b75a7d8f
A
39
40OpenTypeLayoutEngine::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
58void 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
67OpenTypeLayoutEngine::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
74OpenTypeLayoutEngine::~OpenTypeLayoutEngine()
75{
76 reset();
77}
78
79LETag OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode)
80{
81 if (scriptCode < 0 || scriptCode >= scriptCodeCount) {
82 return 0xFFFFFFFF;
83 }
84
85 return scriptTags[scriptCode];
86}
87
88LETag OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode)
89{
90 if (languageCode < 0 || languageCode >= languageCodeCount) {
91 return 0xFFFFFFFF;
92 }
93
94 return languageTags[languageCode];
95}
96
97void OpenTypeLayoutEngine::setScriptAndLanguageTags()
98{
99 fScriptTag = getScriptTag(fScriptCode);
100 fLangSysTag = getLangSysTag(fLanguageCode);
101}
102
374ca955
A
103le_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
133le_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
158le_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
172le_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
204void 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
284U_NAMESPACE_END