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