]> git.saurik.com Git - apple/icu.git/blob - icuSources/layout/LayoutEngine.cpp
ICU-6.2.8.tar.gz
[apple/icu.git] / icuSources / layout / LayoutEngine.cpp
1
2 /*
3 *
4 * (C) Copyright IBM Corp. 1998-2004 - 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 "ArabicLayoutEngine.h"
14 #include "CanonShaping.h"
15 #include "HanLayoutEngine.h"
16 #include "IndicLayoutEngine.h"
17 #include "ThaiLayoutEngine.h"
18 #include "GXLayoutEngine.h"
19 #include "ScriptAndLanguageTags.h"
20 #include "CharSubstitutionFilter.h"
21
22 #include "LEGlyphStorage.h"
23
24 #include "OpenTypeUtilities.h"
25 #include "GlyphSubstitutionTables.h"
26 #include "MorphTables.h"
27
28 #include "DefaultCharMapper.h"
29
30 U_NAMESPACE_BEGIN
31
32 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
33
34 const LEUnicode32 DefaultCharMapper::controlChars[] = {
35 0x0009, 0x000A, 0x000D,
36 /*0x200C, 0x200D,*/ 0x200E, 0x200F,
37 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
38 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
39 };
40
41 const le_int32 DefaultCharMapper::controlCharsCount = ARRAY_SIZE(controlChars);
42
43 const LEUnicode32 DefaultCharMapper::mirroredChars[] = {
44 0x0028, 0x0029, // ascii paired punctuation
45 0x003c, 0x003e,
46 0x005b, 0x005d,
47 0x007b, 0x007d,
48 0x2045, 0x2046, // math symbols (not complete)
49 0x207d, 0x207e,
50 0x208d, 0x208e,
51 0x2264, 0x2265,
52 0x3008, 0x3009, // chinese paired punctuation
53 0x300a, 0x300b,
54 0x300c, 0x300d,
55 0x300e, 0x300f,
56 0x3010, 0x3011,
57 0x3014, 0x3015,
58 0x3016, 0x3017,
59 0x3018, 0x3019,
60 0x301a, 0x301b
61 };
62
63 const le_int32 DefaultCharMapper::mirroredCharsCount = ARRAY_SIZE(mirroredChars);
64
65 LEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch) const
66 {
67 if (fFilterControls) {
68 le_int32 index = OpenTypeUtilities::search((le_uint32)ch, (le_uint32 *)controlChars, controlCharsCount);
69
70 if (controlChars[index] == ch) {
71 return 0xFFFF;
72 }
73 }
74
75 if (fMirror) {
76 le_int32 index = OpenTypeUtilities::search((le_uint32) ch, (le_uint32 *)mirroredChars, mirroredCharsCount);
77
78 if (mirroredChars[index] == ch) {
79 le_int32 mirrorOffset = ((index & 1) == 0) ? 1 : -1;
80
81 return mirroredChars[index + mirrorOffset];
82 }
83 }
84
85 return ch;
86 }
87
88 // This is here to get it out of LEGlyphFilter.h.
89 // No particular reason to put it here, other than
90 // this is a good central location...
91 LEGlyphFilter::~LEGlyphFilter()
92 {
93 // nothing to do
94 }
95
96 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance)
97 : fFontInstance(fontInstance)
98 {
99 // nothing to do
100 }
101
102 CharSubstitutionFilter::~CharSubstitutionFilter()
103 {
104 // nothing to do
105 }
106
107
108 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine)
109
110 static const LETag emptyTag = 0x00000000;
111
112 static const LETag ccmpFeatureTag = LE_CCMP_FEATURE_TAG;
113
114 static const LETag canonFeatures[] = {ccmpFeatureTag, emptyTag};
115
116 LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode)
117 : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode)
118 {
119 fGlyphStorage = new LEGlyphStorage();
120 }
121
122 le_int32 LayoutEngine::getGlyphCount() const
123 {
124 return fGlyphStorage->getGlyphCount();
125 };
126
127 void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
128 {
129 fGlyphStorage->getCharIndices(charIndices, indexBase, success);
130 }
131
132 void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
133 {
134 fGlyphStorage->getCharIndices(charIndices, success);
135 }
136
137 // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
138 void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
139 {
140 fGlyphStorage->getGlyphs(glyphs, extraBits, success);
141 }
142
143 void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
144 {
145 fGlyphStorage->getGlyphs(glyphs, success);
146 }
147
148
149 void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const
150 {
151 fGlyphStorage->getGlyphPositions(positions, success);
152 }
153
154 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
155 {
156 fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success);
157 }
158
159 le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
160 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
161 {
162 if (LE_FAILURE(success)) {
163 return 0;
164 }
165
166 if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
167 success = LE_ILLEGAL_ARGUMENT_ERROR;
168 return 0;
169 }
170
171 const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
172 LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode);
173 LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode);
174 le_int32 i, dir = 1, out = 0, outCharCount = count;
175
176 if (canonGSUBTable->coversScript(scriptTag)) {
177 CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance);
178
179 glyphStorage.allocateGlyphArray(count, rightToLeft, success);
180 glyphStorage.allocateAuxData(success);
181
182 if (LE_FAILURE(success)) {
183 return 0;
184 }
185
186 if (rightToLeft) {
187 out = count - 1;
188 dir = -1;
189 }
190
191 for (i = 0; i < count; i += 1, out += dir) {
192 glyphStorage[out] = (LEGlyphID) chars[offset + i];
193 glyphStorage.setAuxData(out, (void *) canonFeatures, success);
194 }
195
196 outCharCount = canonGSUBTable->process(glyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, NULL);
197
198 out = (rightToLeft? count - 1 : 0);
199
200 outChars = LE_NEW_ARRAY(LEUnicode, outCharCount);
201 for (i = 0; i < outCharCount; i += 1, out += dir) {
202 outChars[out] = (LEUnicode) LE_GET_GLYPH(glyphStorage[i]);
203 }
204
205 delete substitutionFilter;
206 }
207
208 return outCharCount;
209 }
210
211 le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
212 LEGlyphStorage &glyphStorage, LEErrorCode &success)
213 {
214 if (LE_FAILURE(success)) {
215 return 0;
216 }
217
218 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
219 success = LE_ILLEGAL_ARGUMENT_ERROR;
220 return 0;
221 }
222
223 LEUnicode *outChars = NULL;
224 le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success);
225
226 if (outChars != NULL) {
227 mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success);
228 LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
229 } else {
230 mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
231 }
232
233 return glyphStorage.getGlyphCount();
234 }
235
236 // Input: glyphs
237 // Output: positions
238 void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success)
239 {
240 if (LE_FAILURE(success)) {
241 return;
242 }
243
244 glyphStorage.allocatePositions(success);
245
246 if (LE_FAILURE(success)) {
247 return;
248 }
249
250 le_int32 i, glyphCount = glyphStorage.getGlyphCount();
251
252 for (i = 0; i < glyphCount; i += 1) {
253 LEPoint advance;
254
255 glyphStorage.setPosition(i, x, y, success);
256
257 fFontInstance->getGlyphAdvance(glyphStorage[i], advance);
258 x += advance.fX;
259 y += advance.fY;
260 }
261
262 glyphStorage.setPosition(glyphCount, x, y, success);
263 }
264
265 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool /*reverse*/,
266 LEGlyphStorage &/*glyphStorage*/, LEErrorCode &success)
267 {
268 if (LE_FAILURE(success)) {
269 return;
270 }
271
272 if (chars == NULL || offset < 0 || count < 0) {
273 success = LE_ILLEGAL_ARGUMENT_ERROR;
274 return;
275 }
276
277 // default is no adjustments
278 return;
279 }
280
281 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
282 {
283 float xAdjust = 0;
284 le_int32 p, glyphCount = glyphStorage.getGlyphCount();
285
286 if (LE_FAILURE(success)) {
287 return;
288 }
289
290 if (markFilter == NULL) {
291 success = LE_ILLEGAL_ARGUMENT_ERROR;
292 return;
293 }
294
295 float ignore, prev;
296
297 glyphStorage.getGlyphPosition(0, prev, ignore, success);
298
299 for (p = 0; p < glyphCount; p += 1) {
300 float next, xAdvance;
301
302 glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
303
304 xAdvance = next - prev;
305 glyphStorage.adjustPosition(p, xAdjust, 0, success);
306
307 if (markFilter->accept(glyphStorage[p])) {
308 xAdjust -= xAdvance;
309 }
310
311 prev = next;
312 }
313
314 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
315 }
316
317 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
318 {
319 float xAdjust = 0;
320 le_int32 c = 0, direction = 1, p;
321 le_int32 glyphCount = glyphStorage.getGlyphCount();
322
323 if (LE_FAILURE(success)) {
324 return;
325 }
326
327 if (markFilter == NULL) {
328 success = LE_ILLEGAL_ARGUMENT_ERROR;
329 return;
330 }
331
332 if (reverse) {
333 c = glyphCount - 1;
334 direction = -1;
335 }
336
337 float ignore, prev;
338
339 glyphStorage.getGlyphPosition(0, prev, ignore, success);
340
341 for (p = 0; p < charCount; p += 1, c += direction) {
342 float next, xAdvance;
343
344 glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
345
346 xAdvance = next - prev;
347 glyphStorage.adjustPosition(p, xAdjust, 0, success);
348
349 if (markFilter->accept(chars[c])) {
350 xAdjust -= xAdvance;
351 }
352
353 prev = next;
354 }
355
356 glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
357 }
358
359 const void *LayoutEngine::getFontTable(LETag tableTag) const
360 {
361 return fFontInstance->getFontTable(tableTag);
362 }
363
364 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
365 LEGlyphStorage &glyphStorage, LEErrorCode &success)
366 {
367 if (LE_FAILURE(success)) {
368 return;
369 }
370
371 glyphStorage.allocateGlyphArray(count, reverse, success);
372
373 DefaultCharMapper charMapper(TRUE, mirror);
374
375 fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, glyphStorage);
376 }
377
378 // Input: characters, font?
379 // Output: glyphs, positions, char indices
380 // Returns: number of glyphs
381 le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
382 float x, float y, LEErrorCode &success)
383 {
384 if (LE_FAILURE(success)) {
385 return 0;
386 }
387
388 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
389 success = LE_ILLEGAL_ARGUMENT_ERROR;
390 return 0;
391 }
392
393 le_int32 glyphCount;
394
395 glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success);
396 positionGlyphs(*fGlyphStorage, x, y, success);
397 adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success);
398
399 return glyphCount;
400 }
401
402 void LayoutEngine::reset()
403 {
404 fGlyphStorage->reset();
405 }
406
407 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success)
408 {
409 static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
410 static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
411
412 if (LE_FAILURE(success)) {
413 return NULL;
414 }
415
416 const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag);
417 LayoutEngine *result = NULL;
418 LETag scriptTag = 0x00000000;
419 LETag languageTag = 0x00000000;
420
421 if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) {
422 switch (scriptCode) {
423 case bengScriptCode:
424 case devaScriptCode:
425 case gujrScriptCode:
426 case kndaScriptCode:
427 case mlymScriptCode:
428 case oryaScriptCode:
429 case guruScriptCode:
430 case tamlScriptCode:
431 case teluScriptCode:
432 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable);
433 break;
434
435 case arabScriptCode:
436 result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable);
437 break;
438
439 case haniScriptCode:
440 languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
441
442 switch (languageCode) {
443 case korLanguageCode:
444 case janLanguageCode:
445 case zhtLanguageCode:
446 case zhsLanguageCode:
447 if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) {
448 result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable);
449 break;
450 }
451
452 // note: falling through to default case.
453 default:
454 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable);
455 break;
456 }
457
458 break;
459
460 default:
461 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable);
462 break;
463 }
464 } else {
465 const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag);
466
467 if (morphTable != NULL) {
468 result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable);
469 } else {
470 switch (scriptCode) {
471 case bengScriptCode:
472 case devaScriptCode:
473 case gujrScriptCode:
474 case kndaScriptCode:
475 case mlymScriptCode:
476 case oryaScriptCode:
477 case guruScriptCode:
478 case tamlScriptCode:
479 case teluScriptCode:
480 {
481 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode);
482 break;
483 }
484
485 case arabScriptCode:
486 //case hebrScriptCode:
487 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode);
488 break;
489
490 //case hebrScriptCode:
491 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode);
492
493 case thaiScriptCode:
494 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode);
495 break;
496
497 default:
498 result = new LayoutEngine(fontInstance, scriptCode, languageCode);
499 break;
500 }
501 }
502 }
503
504 if (result == NULL) {
505 success = LE_MEMORY_ALLOCATION_ERROR;
506 }
507
508 return result;
509 }
510
511 LayoutEngine::~LayoutEngine() {
512 reset();
513 }
514
515 U_NAMESPACE_END