]>
Commit | Line | Data |
---|---|---|
b75a7d8f | 1 | /* |
b331163b | 2 | * (C) Copyright IBM Corp. and others 1998-2015 - All Rights Reserved |
b75a7d8f A |
3 | */ |
4 | ||
5 | #include "LETypes.h" | |
6 | #include "LEScripts.h" | |
7 | #include "LELanguages.h" | |
51004dcb | 8 | #include "LESwaps.h" |
b75a7d8f A |
9 | |
10 | #include "LayoutEngine.h" | |
11 | #include "ArabicLayoutEngine.h" | |
374ca955 | 12 | #include "CanonShaping.h" |
b75a7d8f | 13 | #include "HanLayoutEngine.h" |
73c04bcf | 14 | #include "HangulLayoutEngine.h" |
b75a7d8f | 15 | #include "IndicLayoutEngine.h" |
73c04bcf | 16 | #include "KhmerLayoutEngine.h" |
b75a7d8f | 17 | #include "ThaiLayoutEngine.h" |
73c04bcf | 18 | #include "TibetanLayoutEngine.h" |
b75a7d8f | 19 | #include "GXLayoutEngine.h" |
51004dcb A |
20 | #include "GXLayoutEngine2.h" |
21 | ||
b75a7d8f | 22 | #include "ScriptAndLanguageTags.h" |
374ca955 A |
23 | #include "CharSubstitutionFilter.h" |
24 | ||
25 | #include "LEGlyphStorage.h" | |
b75a7d8f A |
26 | |
27 | #include "OpenTypeUtilities.h" | |
28 | #include "GlyphSubstitutionTables.h" | |
46f4442e | 29 | #include "GlyphDefinitionTables.h" |
b75a7d8f A |
30 | #include "MorphTables.h" |
31 | ||
32 | #include "DefaultCharMapper.h" | |
33 | ||
73c04bcf | 34 | #include "KernTable.h" |
b75a7d8f | 35 | |
73c04bcf | 36 | U_NAMESPACE_BEGIN |
b75a7d8f | 37 | |
46f4442e A |
38 | /* Leave this copyright notice here! It needs to go somewhere in this library. */ |
39 | static const char copyright[] = U_COPYRIGHT_STRING; | |
40 | ||
51004dcb A |
41 | /* TODO: remove these? */ |
42 | const le_int32 LayoutEngine::kTypoFlagKern = LE_Kerning_FEATURE_FLAG; | |
43 | const le_int32 LayoutEngine::kTypoFlagLiga = LE_Ligatures_FEATURE_FLAG; | |
4388f060 | 44 | |
b75a7d8f A |
45 | const LEUnicode32 DefaultCharMapper::controlChars[] = { |
46 | 0x0009, 0x000A, 0x000D, | |
47 | /*0x200C, 0x200D,*/ 0x200E, 0x200F, | |
48 | 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, | |
49 | 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F | |
50 | }; | |
51 | ||
73c04bcf | 52 | const le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars); |
b75a7d8f A |
53 | |
54 | LEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch) const | |
55 | { | |
57a6839d | 56 | (void)copyright; // Suppress unused variable warning. |
b75a7d8f A |
57 | if (fFilterControls) { |
58 | le_int32 index = OpenTypeUtilities::search((le_uint32)ch, (le_uint32 *)controlChars, controlCharsCount); | |
59 | ||
60 | if (controlChars[index] == ch) { | |
61 | return 0xFFFF; | |
62 | } | |
63 | } | |
64 | ||
65 | if (fMirror) { | |
73c04bcf | 66 | le_int32 index = OpenTypeUtilities::search((le_uint32) ch, (le_uint32 *)DefaultCharMapper::mirroredChars, DefaultCharMapper::mirroredCharsCount); |
b75a7d8f A |
67 | |
68 | if (mirroredChars[index] == ch) { | |
73c04bcf | 69 | return DefaultCharMapper::srahCderorrim[index]; |
b75a7d8f A |
70 | } |
71 | } | |
72 | ||
73 | return ch; | |
74 | } | |
75 | ||
374ca955 A |
76 | // This is here to get it out of LEGlyphFilter.h. |
77 | // No particular reason to put it here, other than | |
78 | // this is a good central location... | |
79 | LEGlyphFilter::~LEGlyphFilter() | |
80 | { | |
81 | // nothing to do | |
82 | } | |
b75a7d8f | 83 | |
374ca955 A |
84 | CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance) |
85 | : fFontInstance(fontInstance) | |
b75a7d8f | 86 | { |
374ca955 | 87 | // nothing to do |
b75a7d8f A |
88 | } |
89 | ||
374ca955 | 90 | CharSubstitutionFilter::~CharSubstitutionFilter() |
b75a7d8f | 91 | { |
374ca955 A |
92 | // nothing to do |
93 | } | |
b75a7d8f | 94 | |
46f4442e A |
95 | class CanonMarkFilter : public UMemory, public LEGlyphFilter |
96 | { | |
97 | private: | |
57a6839d | 98 | const LEReferenceTo<GlyphClassDefinitionTable> classDefTable; |
46f4442e A |
99 | |
100 | CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class | |
101 | CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class | |
102 | ||
103 | public: | |
57a6839d | 104 | CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success); |
46f4442e A |
105 | virtual ~CanonMarkFilter(); |
106 | ||
107 | virtual le_bool accept(LEGlyphID glyph) const; | |
108 | }; | |
109 | ||
57a6839d A |
110 | CanonMarkFilter::CanonMarkFilter(const LEReferenceTo<GlyphDefinitionTableHeader> &gdefTable, LEErrorCode &success) |
111 | : classDefTable(gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success)) | |
46f4442e | 112 | { |
46f4442e A |
113 | } |
114 | ||
115 | CanonMarkFilter::~CanonMarkFilter() | |
116 | { | |
117 | // nothing to do? | |
118 | } | |
119 | ||
120 | le_bool CanonMarkFilter::accept(LEGlyphID glyph) const | |
121 | { | |
57a6839d A |
122 | LEErrorCode success = LE_NO_ERROR; |
123 | le_int32 glyphClass = classDefTable->getGlyphClass(classDefTable, glyph, success); | |
124 | if(LE_FAILURE(success)) return false; | |
125 | return glyphClass != 0; | |
46f4442e | 126 | } |
b75a7d8f | 127 | |
374ca955 | 128 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine) |
b75a7d8f | 129 | |
73c04bcf | 130 | #define ccmpFeatureTag LE_CCMP_FEATURE_TAG |
b75a7d8f | 131 | |
73c04bcf A |
132 | #define ccmpFeatureMask 0x80000000UL |
133 | ||
134 | #define canonFeatures (ccmpFeatureMask) | |
135 | ||
136 | static const FeatureMap canonFeatureMap[] = | |
137 | { | |
138 | {ccmpFeatureTag, ccmpFeatureMask} | |
139 | }; | |
374ca955 | 140 | |
73c04bcf | 141 | static const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap); |
374ca955 | 142 | |
51004dcb A |
143 | LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, |
144 | le_int32 scriptCode, | |
145 | le_int32 languageCode, | |
729e4ab9 A |
146 | le_int32 typoFlags, |
147 | LEErrorCode &success) | |
73c04bcf | 148 | : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode), |
46f4442e | 149 | fTypoFlags(typoFlags), fFilterZeroWidth(TRUE) |
374ca955 | 150 | { |
729e4ab9 A |
151 | if (LE_FAILURE(success)) { |
152 | return; | |
51004dcb | 153 | } |
729e4ab9 | 154 | |
374ca955 | 155 | fGlyphStorage = new LEGlyphStorage(); |
729e4ab9 A |
156 | if (fGlyphStorage == NULL) { |
157 | success = LE_MEMORY_ALLOCATION_ERROR; | |
158 | } | |
374ca955 A |
159 | } |
160 | ||
161 | le_int32 LayoutEngine::getGlyphCount() const | |
162 | { | |
163 | return fGlyphStorage->getGlyphCount(); | |
73c04bcf | 164 | } |
374ca955 A |
165 | |
166 | void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const | |
167 | { | |
168 | fGlyphStorage->getCharIndices(charIndices, indexBase, success); | |
b75a7d8f A |
169 | } |
170 | ||
171 | void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const | |
172 | { | |
374ca955 | 173 | fGlyphStorage->getCharIndices(charIndices, success); |
b75a7d8f A |
174 | } |
175 | ||
176 | // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits | |
177 | void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const | |
178 | { | |
374ca955 | 179 | fGlyphStorage->getGlyphs(glyphs, extraBits, success); |
b75a7d8f A |
180 | } |
181 | ||
182 | void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const | |
183 | { | |
374ca955 | 184 | fGlyphStorage->getGlyphs(glyphs, success); |
b75a7d8f A |
185 | } |
186 | ||
187 | ||
188 | void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const | |
189 | { | |
374ca955 | 190 | fGlyphStorage->getGlyphPositions(positions, success); |
b75a7d8f A |
191 | } |
192 | ||
193 | void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const | |
374ca955 A |
194 | { |
195 | fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success); | |
196 | } | |
197 | ||
198 | le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, | |
46f4442e | 199 | LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) |
b75a7d8f A |
200 | { |
201 | if (LE_FAILURE(success)) { | |
374ca955 | 202 | return 0; |
b75a7d8f | 203 | } |
374ca955 A |
204 | |
205 | if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { | |
206 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
207 | return 0; | |
b75a7d8f | 208 | } |
374ca955 | 209 | |
57a6839d | 210 | LEReferenceTo<GlyphSubstitutionTableHeader> canonGSUBTable((GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable); |
374ca955 A |
211 | LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); |
212 | LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); | |
213 | le_int32 i, dir = 1, out = 0, outCharCount = count; | |
214 | ||
57a6839d | 215 | if (canonGSUBTable->coversScript(canonGSUBTable,scriptTag, success) || LE_SUCCESS(success)) { |
374ca955 | 216 | CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); |
51004dcb | 217 | if (substitutionFilter == NULL) { |
729e4ab9 A |
218 | success = LE_MEMORY_ALLOCATION_ERROR; |
219 | return 0; | |
220 | } | |
221 | ||
57a6839d A |
222 | const LEUnicode *inChars = &chars[offset]; |
223 | LEUnicode *reordered = NULL; | |
73c04bcf | 224 | LEGlyphStorage fakeGlyphStorage; |
374ca955 | 225 | |
73c04bcf A |
226 | fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); |
227 | ||
228 | if (LE_FAILURE(success)) { | |
729e4ab9 | 229 | delete substitutionFilter; |
73c04bcf A |
230 | return 0; |
231 | } | |
232 | ||
57a6839d A |
233 | // This is the cheapest way to get mark reordering only for Hebrew. |
234 | // We could just do the mark reordering for all scripts, but most | |
235 | // of them probably don't need it... | |
236 | if (fScriptCode == hebrScriptCode) { | |
237 | reordered = LE_NEW_ARRAY(LEUnicode, count); | |
238 | ||
239 | if (reordered == NULL) { | |
240 | delete substitutionFilter; | |
241 | success = LE_MEMORY_ALLOCATION_ERROR; | |
242 | return 0; | |
243 | } | |
244 | ||
245 | CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); | |
246 | inChars = reordered; | |
73c04bcf A |
247 | } |
248 | ||
249 | fakeGlyphStorage.allocateAuxData(success); | |
374ca955 A |
250 | |
251 | if (LE_FAILURE(success)) { | |
729e4ab9 | 252 | delete substitutionFilter; |
374ca955 A |
253 | return 0; |
254 | } | |
255 | ||
256 | if (rightToLeft) { | |
257 | out = count - 1; | |
258 | dir = -1; | |
259 | } | |
260 | ||
261 | for (i = 0; i < count; i += 1, out += dir) { | |
73c04bcf A |
262 | fakeGlyphStorage[out] = (LEGlyphID) inChars[i]; |
263 | fakeGlyphStorage.setAuxData(out, canonFeatures, success); | |
374ca955 A |
264 | } |
265 | ||
57a6839d A |
266 | if (reordered != NULL) { |
267 | LE_DELETE_ARRAY(reordered); | |
268 | } | |
73c04bcf | 269 | |
57a6839d | 270 | outCharCount = canonGSUBTable->process(canonGSUBTable, fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, (const GlyphDefinitionTableHeader*)NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); |
729e4ab9 A |
271 | |
272 | if (LE_FAILURE(success)) { | |
273 | delete substitutionFilter; | |
274 | return 0; | |
275 | } | |
374ca955 | 276 | |
73c04bcf | 277 | out = (rightToLeft? outCharCount - 1 : 0); |
374ca955 | 278 | |
46f4442e A |
279 | /* |
280 | * The char indices array in fakeGlyphStorage has the correct mapping | |
281 | * back to the original input characters. Save it in glyphStorage. The | |
282 | * subsequent call to glyphStoratge.allocateGlyphArray will keep this | |
283 | * array rather than allocating and initializing a new one. | |
284 | */ | |
285 | glyphStorage.adoptCharIndicesArray(fakeGlyphStorage); | |
286 | ||
374ca955 | 287 | outChars = LE_NEW_ARRAY(LEUnicode, outCharCount); |
729e4ab9 A |
288 | |
289 | if (outChars == NULL) { | |
290 | delete substitutionFilter; | |
291 | success = LE_MEMORY_ALLOCATION_ERROR; | |
292 | return 0; | |
293 | } | |
294 | ||
374ca955 | 295 | for (i = 0; i < outCharCount; i += 1, out += dir) { |
73c04bcf | 296 | outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]); |
374ca955 A |
297 | } |
298 | ||
299 | delete substitutionFilter; | |
b75a7d8f | 300 | } |
b75a7d8f | 301 | |
374ca955 A |
302 | return outCharCount; |
303 | } | |
b75a7d8f A |
304 | |
305 | le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, | |
374ca955 | 306 | LEGlyphStorage &glyphStorage, LEErrorCode &success) |
b75a7d8f A |
307 | { |
308 | if (LE_FAILURE(success)) { | |
309 | return 0; | |
310 | } | |
311 | ||
312 | if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { | |
313 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
314 | return 0; | |
315 | } | |
316 | ||
374ca955 A |
317 | LEUnicode *outChars = NULL; |
318 | le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success); | |
b75a7d8f | 319 | |
374ca955 | 320 | if (outChars != NULL) { |
46f4442e | 321 | mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success); |
374ca955 A |
322 | LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... |
323 | } else { | |
46f4442e | 324 | mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success); |
374ca955 A |
325 | } |
326 | ||
327 | return glyphStorage.getGlyphCount(); | |
b75a7d8f A |
328 | } |
329 | ||
330 | // Input: glyphs | |
331 | // Output: positions | |
374ca955 | 332 | void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success) |
b75a7d8f A |
333 | { |
334 | if (LE_FAILURE(success)) { | |
335 | return; | |
336 | } | |
337 | ||
374ca955 | 338 | glyphStorage.allocatePositions(success); |
b75a7d8f | 339 | |
374ca955 A |
340 | if (LE_FAILURE(success)) { |
341 | return; | |
b75a7d8f A |
342 | } |
343 | ||
374ca955 | 344 | le_int32 i, glyphCount = glyphStorage.getGlyphCount(); |
b75a7d8f A |
345 | |
346 | for (i = 0; i < glyphCount; i += 1) { | |
347 | LEPoint advance; | |
348 | ||
374ca955 | 349 | glyphStorage.setPosition(i, x, y, success); |
b75a7d8f | 350 | |
374ca955 | 351 | fFontInstance->getGlyphAdvance(glyphStorage[i], advance); |
b75a7d8f A |
352 | x += advance.fX; |
353 | y += advance.fY; | |
354 | } | |
355 | ||
374ca955 | 356 | glyphStorage.setPosition(glyphCount, x, y, success); |
b75a7d8f A |
357 | } |
358 | ||
46f4442e | 359 | void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, |
73c04bcf | 360 | LEGlyphStorage &glyphStorage, LEErrorCode &success) |
374ca955 A |
361 | { |
362 | if (LE_FAILURE(success)) { | |
363 | return; | |
364 | } | |
365 | ||
366 | if (chars == NULL || offset < 0 || count < 0) { | |
367 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
368 | return; | |
369 | } | |
370 | ||
57a6839d A |
371 | LEReferenceTo<GlyphDefinitionTableHeader> gdefTable((GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable, |
372 | CanonShaping::glyphDefinitionTableLen); | |
373 | CanonMarkFilter filter(gdefTable, success); | |
46f4442e A |
374 | |
375 | adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); | |
376 | ||
57a6839d A |
377 | if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ |
378 | LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); | |
379 | KernTable kt(kernTable, success); | |
380 | kt.process(glyphStorage, success); | |
73c04bcf A |
381 | } |
382 | ||
374ca955 A |
383 | // default is no adjustments |
384 | return; | |
385 | } | |
386 | ||
387 | void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success) | |
b75a7d8f A |
388 | { |
389 | float xAdjust = 0; | |
374ca955 | 390 | le_int32 p, glyphCount = glyphStorage.getGlyphCount(); |
b75a7d8f A |
391 | |
392 | if (LE_FAILURE(success)) { | |
393 | return; | |
394 | } | |
395 | ||
374ca955 | 396 | if (markFilter == NULL) { |
b75a7d8f A |
397 | success = LE_ILLEGAL_ARGUMENT_ERROR; |
398 | return; | |
399 | } | |
400 | ||
374ca955 | 401 | float ignore, prev; |
b75a7d8f | 402 | |
374ca955 | 403 | glyphStorage.getGlyphPosition(0, prev, ignore, success); |
b75a7d8f | 404 | |
374ca955 A |
405 | for (p = 0; p < glyphCount; p += 1) { |
406 | float next, xAdvance; | |
51004dcb | 407 | |
374ca955 | 408 | glyphStorage.getGlyphPosition(p + 1, next, ignore, success); |
b75a7d8f | 409 | |
374ca955 A |
410 | xAdvance = next - prev; |
411 | glyphStorage.adjustPosition(p, xAdjust, 0, success); | |
412 | ||
413 | if (markFilter->accept(glyphStorage[p])) { | |
b75a7d8f A |
414 | xAdjust -= xAdvance; |
415 | } | |
374ca955 A |
416 | |
417 | prev = next; | |
b75a7d8f A |
418 | } |
419 | ||
374ca955 | 420 | glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); |
b75a7d8f A |
421 | } |
422 | ||
374ca955 | 423 | void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success) |
b75a7d8f | 424 | { |
374ca955 A |
425 | float xAdjust = 0; |
426 | le_int32 c = 0, direction = 1, p; | |
427 | le_int32 glyphCount = glyphStorage.getGlyphCount(); | |
b75a7d8f | 428 | |
b75a7d8f A |
429 | if (LE_FAILURE(success)) { |
430 | return; | |
431 | } | |
432 | ||
374ca955 | 433 | if (markFilter == NULL) { |
b75a7d8f A |
434 | success = LE_ILLEGAL_ARGUMENT_ERROR; |
435 | return; | |
436 | } | |
437 | ||
374ca955 A |
438 | if (reverse) { |
439 | c = glyphCount - 1; | |
440 | direction = -1; | |
b75a7d8f A |
441 | } |
442 | ||
374ca955 | 443 | float ignore, prev; |
b75a7d8f | 444 | |
374ca955 | 445 | glyphStorage.getGlyphPosition(0, prev, ignore, success); |
b75a7d8f | 446 | |
374ca955 A |
447 | for (p = 0; p < charCount; p += 1, c += direction) { |
448 | float next, xAdvance; | |
51004dcb | 449 | |
374ca955 | 450 | glyphStorage.getGlyphPosition(p + 1, next, ignore, success); |
b75a7d8f | 451 | |
374ca955 A |
452 | xAdvance = next - prev; |
453 | glyphStorage.adjustPosition(p, xAdjust, 0, success); | |
b75a7d8f | 454 | |
374ca955 A |
455 | if (markFilter->accept(chars[c])) { |
456 | xAdjust -= xAdvance; | |
b75a7d8f | 457 | } |
374ca955 A |
458 | |
459 | prev = next; | |
460 | } | |
461 | ||
462 | glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); | |
463 | } | |
464 | ||
57a6839d | 465 | const void *LayoutEngine::getFontTable(LETag tableTag, size_t &length) const |
374ca955 | 466 | { |
57a6839d | 467 | return fFontInstance->getFontTable(tableTag, length); |
374ca955 A |
468 | } |
469 | ||
46f4442e | 470 | void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, |
374ca955 A |
471 | LEGlyphStorage &glyphStorage, LEErrorCode &success) |
472 | { | |
473 | if (LE_FAILURE(success)) { | |
474 | return; | |
b75a7d8f A |
475 | } |
476 | ||
374ca955 | 477 | glyphStorage.allocateGlyphArray(count, reverse, success); |
b75a7d8f | 478 | |
374ca955 A |
479 | DefaultCharMapper charMapper(TRUE, mirror); |
480 | ||
46f4442e | 481 | fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, fFilterZeroWidth, glyphStorage); |
b75a7d8f A |
482 | } |
483 | ||
484 | // Input: characters, font? | |
485 | // Output: glyphs, positions, char indices | |
486 | // Returns: number of glyphs | |
487 | le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, | |
488 | float x, float y, LEErrorCode &success) | |
489 | { | |
490 | if (LE_FAILURE(success)) { | |
491 | return 0; | |
492 | } | |
493 | ||
494 | if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { | |
495 | success = LE_ILLEGAL_ARGUMENT_ERROR; | |
496 | return 0; | |
497 | } | |
498 | ||
374ca955 | 499 | le_int32 glyphCount; |
73c04bcf A |
500 | |
501 | if (fGlyphStorage->getGlyphCount() > 0) { | |
502 | fGlyphStorage->reset(); | |
503 | } | |
51004dcb | 504 | |
374ca955 A |
505 | glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success); |
506 | positionGlyphs(*fGlyphStorage, x, y, success); | |
507 | adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success); | |
b75a7d8f | 508 | |
374ca955 | 509 | return glyphCount; |
b75a7d8f A |
510 | } |
511 | ||
512 | void LayoutEngine::reset() | |
513 | { | |
57a6839d | 514 | if(fGlyphStorage!=NULL) { |
374ca955 | 515 | fGlyphStorage->reset(); |
57a6839d | 516 | } |
b75a7d8f | 517 | } |
51004dcb | 518 | |
b75a7d8f | 519 | LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success) |
73c04bcf | 520 | { |
57a6839d A |
521 | //kerning and ligatures - by default |
522 | return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, LE_DEFAULT_FEATURE_FLAG, success); | |
73c04bcf | 523 | } |
51004dcb | 524 | |
73c04bcf | 525 | LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) |
b75a7d8f | 526 | { |
374ca955 A |
527 | static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG; |
528 | static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG; | |
51004dcb | 529 | static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG; |
b75a7d8f A |
530 | |
531 | if (LE_FAILURE(success)) { | |
532 | return NULL; | |
533 | } | |
534 | ||
57a6839d | 535 | LEReferenceTo<GlyphSubstitutionTableHeader> gsubTable(fontInstance,gsubTableTag,success); |
b75a7d8f A |
536 | LayoutEngine *result = NULL; |
537 | LETag scriptTag = 0x00000000; | |
538 | LETag languageTag = 0x00000000; | |
57a6839d | 539 | LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); |
b75a7d8f | 540 | |
729e4ab9 A |
541 | // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are |
542 | // properly tested. | |
543 | ||
57a6839d A |
544 | if ( v2ScriptTag == dev2ScriptTag && gsubTable.isValid() && gsubTable->coversScript(gsubTable, v2ScriptTag, success )) { |
545 | result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); | |
546 | } | |
547 | else if (gsubTable.isValid() && gsubTable->coversScript(gsubTable, scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode), success)) { | |
b75a7d8f A |
548 | switch (scriptCode) { |
549 | case bengScriptCode: | |
550 | case devaScriptCode: | |
551 | case gujrScriptCode: | |
552 | case kndaScriptCode: | |
553 | case mlymScriptCode: | |
554 | case oryaScriptCode: | |
555 | case guruScriptCode: | |
556 | case tamlScriptCode: | |
557 | case teluScriptCode: | |
73c04bcf | 558 | case sinhScriptCode: |
729e4ab9 | 559 | result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success); |
b75a7d8f A |
560 | break; |
561 | ||
562 | case arabScriptCode: | |
729e4ab9 | 563 | result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
73c04bcf A |
564 | break; |
565 | ||
4388f060 A |
566 | case hebrScriptCode: |
567 | // Disable hebrew ligatures since they have only archaic uses, see ticket #8318 | |
568 | result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success); | |
569 | break; | |
570 | ||
73c04bcf | 571 | case hangScriptCode: |
729e4ab9 | 572 | result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
b75a7d8f A |
573 | break; |
574 | ||
575 | case haniScriptCode: | |
576 | languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode); | |
577 | ||
578 | switch (languageCode) { | |
579 | case korLanguageCode: | |
580 | case janLanguageCode: | |
581 | case zhtLanguageCode: | |
582 | case zhsLanguageCode: | |
57a6839d | 583 | if (gsubTable->coversScriptAndLanguage(gsubTable, scriptTag, languageTag, success, TRUE)) { |
729e4ab9 | 584 | result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
b75a7d8f | 585 | break; |
57a6839d | 586 | } |
b75a7d8f A |
587 | |
588 | // note: falling through to default case. | |
589 | default: | |
729e4ab9 | 590 | result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
b75a7d8f A |
591 | break; |
592 | } | |
593 | ||
594 | break; | |
595 | ||
73c04bcf | 596 | case tibtScriptCode: |
729e4ab9 | 597 | result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
73c04bcf A |
598 | break; |
599 | ||
600 | case khmrScriptCode: | |
729e4ab9 | 601 | result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
73c04bcf A |
602 | break; |
603 | ||
b75a7d8f | 604 | default: |
729e4ab9 | 605 | result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); |
b75a7d8f A |
606 | break; |
607 | } | |
608 | } else { | |
b331163b A |
609 | LEReferenceTo<MorphTableHeader2> morxTable(fontInstance, morxTableTag, success); |
610 | if (LE_SUCCESS(success) && morxTable.isValid() && SWAPL(morxTable->version)==0x00020000) { | |
611 | result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); | |
b75a7d8f | 612 | } else { |
57a6839d A |
613 | LEReferenceTo<MorphTableHeader> mortTable(fontInstance, mortTableTag, success); |
614 | if (LE_SUCCESS(success) && mortTable.isValid() && SWAPL(mortTable->version)==0x00010000) { // mort | |
615 | result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); | |
51004dcb A |
616 | } else { |
617 | switch (scriptCode) { | |
618 | case bengScriptCode: | |
619 | case devaScriptCode: | |
620 | case gujrScriptCode: | |
621 | case kndaScriptCode: | |
622 | case mlymScriptCode: | |
623 | case oryaScriptCode: | |
624 | case guruScriptCode: | |
625 | case tamlScriptCode: | |
626 | case teluScriptCode: | |
627 | case sinhScriptCode: | |
628 | { | |
629 | result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); | |
630 | break; | |
631 | } | |
632 | ||
633 | case arabScriptCode: | |
634 | //case hebrScriptCode: | |
635 | result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); | |
636 | break; | |
637 | ||
638 | //case hebrScriptCode: | |
639 | // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); | |
640 | ||
641 | case thaiScriptCode: | |
642 | result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); | |
643 | break; | |
644 | ||
645 | case hangScriptCode: | |
646 | result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); | |
647 | break; | |
648 | ||
649 | default: | |
650 | result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); | |
651 | break; | |
652 | } | |
b75a7d8f A |
653 | } |
654 | } | |
655 | } | |
656 | ||
729e4ab9 A |
657 | if (result && LE_FAILURE(success)) { |
658 | delete result; | |
659 | result = NULL; | |
660 | } | |
661 | ||
b75a7d8f A |
662 | if (result == NULL) { |
663 | success = LE_MEMORY_ALLOCATION_ERROR; | |
664 | } | |
665 | ||
666 | return result; | |
667 | } | |
668 | ||
669 | LayoutEngine::~LayoutEngine() { | |
73c04bcf | 670 | delete fGlyphStorage; |
b75a7d8f A |
671 | } |
672 | ||
673 | U_NAMESPACE_END |