4 * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
10 #include "LELanguages.h"
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"
22 #include "LEGlyphStorage.h"
24 #include "OpenTypeUtilities.h"
25 #include "GlyphSubstitutionTables.h"
26 #include "MorphTables.h"
28 #include "DefaultCharMapper.h"
32 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
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
41 const le_int32
DefaultCharMapper::controlCharsCount
= ARRAY_SIZE(controlChars
);
43 const LEUnicode32
DefaultCharMapper::mirroredChars
[] = {
44 0x0028, 0x0029, // ascii paired punctuation
48 0x2045, 0x2046, // math symbols (not complete)
52 0x3008, 0x3009, // chinese paired punctuation
63 const le_int32
DefaultCharMapper::mirroredCharsCount
= ARRAY_SIZE(mirroredChars
);
65 LEUnicode32
DefaultCharMapper::mapChar(LEUnicode32 ch
) const
67 if (fFilterControls
) {
68 le_int32 index
= OpenTypeUtilities::search((le_uint32
)ch
, (le_uint32
*)controlChars
, controlCharsCount
);
70 if (controlChars
[index
] == ch
) {
76 le_int32 index
= OpenTypeUtilities::search((le_uint32
) ch
, (le_uint32
*)mirroredChars
, mirroredCharsCount
);
78 if (mirroredChars
[index
] == ch
) {
79 le_int32 mirrorOffset
= ((index
& 1) == 0) ? 1 : -1;
81 return mirroredChars
[index
+ mirrorOffset
];
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()
96 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance
*fontInstance
)
97 : fFontInstance(fontInstance
)
102 CharSubstitutionFilter::~CharSubstitutionFilter()
108 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine
)
110 static const LETag emptyTag
= 0x00000000;
112 static const LETag ccmpFeatureTag
= LE_CCMP_FEATURE_TAG
;
114 static const LETag canonFeatures
[] = {ccmpFeatureTag
, emptyTag
};
116 LayoutEngine::LayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
)
117 : fGlyphStorage(NULL
), fFontInstance(fontInstance
), fScriptCode(scriptCode
), fLanguageCode(languageCode
)
119 fGlyphStorage
= new LEGlyphStorage();
122 le_int32
LayoutEngine::getGlyphCount() const
124 return fGlyphStorage
->getGlyphCount();
127 void LayoutEngine::getCharIndices(le_int32 charIndices
[], le_int32 indexBase
, LEErrorCode
&success
) const
129 fGlyphStorage
->getCharIndices(charIndices
, indexBase
, success
);
132 void LayoutEngine::getCharIndices(le_int32 charIndices
[], LEErrorCode
&success
) const
134 fGlyphStorage
->getCharIndices(charIndices
, success
);
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
140 fGlyphStorage
->getGlyphs(glyphs
, extraBits
, success
);
143 void LayoutEngine::getGlyphs(LEGlyphID glyphs
[], LEErrorCode
&success
) const
145 fGlyphStorage
->getGlyphs(glyphs
, success
);
149 void LayoutEngine::getGlyphPositions(float positions
[], LEErrorCode
&success
) const
151 fGlyphStorage
->getGlyphPositions(positions
, success
);
154 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex
, float &x
, float &y
, LEErrorCode
&success
) const
156 fGlyphStorage
->getGlyphPosition(glyphIndex
, x
, y
, success
);
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
)
162 if (LE_FAILURE(success
)) {
166 if (offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
167 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
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
;
176 if (canonGSUBTable
->coversScript(scriptTag
)) {
177 CharSubstitutionFilter
*substitutionFilter
= new CharSubstitutionFilter(fFontInstance
);
179 glyphStorage
.allocateGlyphArray(count
, rightToLeft
, success
);
180 glyphStorage
.allocateAuxData(success
);
182 if (LE_FAILURE(success
)) {
191 for (i
= 0; i
< count
; i
+= 1, out
+= dir
) {
192 glyphStorage
[out
] = (LEGlyphID
) chars
[offset
+ i
];
193 glyphStorage
.setAuxData(out
, (void *) canonFeatures
, success
);
196 outCharCount
= canonGSUBTable
->process(glyphStorage
, rightToLeft
, scriptTag
, langSysTag
, NULL
, substitutionFilter
, NULL
);
198 out
= (rightToLeft
? count
- 1 : 0);
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
]);
205 delete substitutionFilter
;
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
)
214 if (LE_FAILURE(success
)) {
218 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
219 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
223 LEUnicode
*outChars
= NULL
;
224 le_int32 outCharCount
= characterProcessing(chars
, offset
, count
, max
, rightToLeft
, outChars
, glyphStorage
, success
);
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...
230 mapCharsToGlyphs(chars
, offset
, count
, rightToLeft
, rightToLeft
, glyphStorage
, success
);
233 return glyphStorage
.getGlyphCount();
238 void LayoutEngine::positionGlyphs(LEGlyphStorage
&glyphStorage
, float x
, float y
, LEErrorCode
&success
)
240 if (LE_FAILURE(success
)) {
244 glyphStorage
.allocatePositions(success
);
246 if (LE_FAILURE(success
)) {
250 le_int32 i
, glyphCount
= glyphStorage
.getGlyphCount();
252 for (i
= 0; i
< glyphCount
; i
+= 1) {
255 glyphStorage
.setPosition(i
, x
, y
, success
);
257 fFontInstance
->getGlyphAdvance(glyphStorage
[i
], advance
);
262 glyphStorage
.setPosition(glyphCount
, x
, y
, success
);
265 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool
/*reverse*/,
266 LEGlyphStorage
&/*glyphStorage*/, LEErrorCode
&success
)
268 if (LE_FAILURE(success
)) {
272 if (chars
== NULL
|| offset
< 0 || count
< 0) {
273 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
277 // default is no adjustments
281 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage
&glyphStorage
, LEGlyphFilter
*markFilter
, LEErrorCode
&success
)
284 le_int32 p
, glyphCount
= glyphStorage
.getGlyphCount();
286 if (LE_FAILURE(success
)) {
290 if (markFilter
== NULL
) {
291 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
297 glyphStorage
.getGlyphPosition(0, prev
, ignore
, success
);
299 for (p
= 0; p
< glyphCount
; p
+= 1) {
300 float next
, xAdvance
;
302 glyphStorage
.getGlyphPosition(p
+ 1, next
, ignore
, success
);
304 xAdvance
= next
- prev
;
305 glyphStorage
.adjustPosition(p
, xAdjust
, 0, success
);
307 if (markFilter
->accept(glyphStorage
[p
])) {
314 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, 0, success
);
317 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars
[], le_int32 charCount
, le_bool reverse
, LEGlyphStorage
&glyphStorage
, LEGlyphFilter
*markFilter
, LEErrorCode
&success
)
320 le_int32 c
= 0, direction
= 1, p
;
321 le_int32 glyphCount
= glyphStorage
.getGlyphCount();
323 if (LE_FAILURE(success
)) {
327 if (markFilter
== NULL
) {
328 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
339 glyphStorage
.getGlyphPosition(0, prev
, ignore
, success
);
341 for (p
= 0; p
< charCount
; p
+= 1, c
+= direction
) {
342 float next
, xAdvance
;
344 glyphStorage
.getGlyphPosition(p
+ 1, next
, ignore
, success
);
346 xAdvance
= next
- prev
;
347 glyphStorage
.adjustPosition(p
, xAdjust
, 0, success
);
349 if (markFilter
->accept(chars
[c
])) {
356 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, 0, success
);
359 const void *LayoutEngine::getFontTable(LETag tableTag
) const
361 return fFontInstance
->getFontTable(tableTag
);
364 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
, le_bool mirror
,
365 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
367 if (LE_FAILURE(success
)) {
371 glyphStorage
.allocateGlyphArray(count
, reverse
, success
);
373 DefaultCharMapper
charMapper(TRUE
, mirror
);
375 fFontInstance
->mapCharsToGlyphs(chars
, offset
, count
, reverse
, &charMapper
, glyphStorage
);
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
)
384 if (LE_FAILURE(success
)) {
388 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
389 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
395 glyphCount
= computeGlyphs(chars
, offset
, count
, max
, rightToLeft
, *fGlyphStorage
, success
);
396 positionGlyphs(*fGlyphStorage
, x
, y
, success
);
397 adjustGlyphPositions(chars
, offset
, count
, rightToLeft
, *fGlyphStorage
, success
);
402 void LayoutEngine::reset()
404 fGlyphStorage
->reset();
407 LayoutEngine
*LayoutEngine::layoutEngineFactory(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, LEErrorCode
&success
)
409 static const le_uint32 gsubTableTag
= LE_GSUB_TABLE_TAG
;
410 static const le_uint32 mortTableTag
= LE_MORT_TABLE_TAG
;
412 if (LE_FAILURE(success
)) {
416 const GlyphSubstitutionTableHeader
*gsubTable
= (const GlyphSubstitutionTableHeader
*) fontInstance
->getFontTable(gsubTableTag
);
417 LayoutEngine
*result
= NULL
;
418 LETag scriptTag
= 0x00000000;
419 LETag languageTag
= 0x00000000;
421 if (gsubTable
!= NULL
&& gsubTable
->coversScript(scriptTag
= OpenTypeLayoutEngine::getScriptTag(scriptCode
))) {
422 switch (scriptCode
) {
432 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, gsubTable
);
436 result
= new ArabicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, gsubTable
);
440 languageTag
= OpenTypeLayoutEngine::getLangSysTag(languageCode
);
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
);
452 // note: falling through to default case.
454 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, gsubTable
);
461 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, gsubTable
);
465 const MorphTableHeader
*morphTable
= (MorphTableHeader
*) fontInstance
->getFontTable(mortTableTag
);
467 if (morphTable
!= NULL
) {
468 result
= new GXLayoutEngine(fontInstance
, scriptCode
, languageCode
, morphTable
);
470 switch (scriptCode
) {
481 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
);
486 //case hebrScriptCode:
487 result
= new UnicodeArabicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
);
490 //case hebrScriptCode:
491 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode);
494 result
= new ThaiLayoutEngine(fontInstance
, scriptCode
, languageCode
);
498 result
= new LayoutEngine(fontInstance
, scriptCode
, languageCode
);
504 if (result
== NULL
) {
505 success
= LE_MEMORY_ALLOCATION_ERROR
;
511 LayoutEngine::~LayoutEngine() {