4 * (C) Copyright IBM Corp. 1998-2006 - 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 "HangulLayoutEngine.h"
17 #include "IndicLayoutEngine.h"
18 #include "KhmerLayoutEngine.h"
19 #include "ThaiLayoutEngine.h"
20 #include "TibetanLayoutEngine.h"
21 #include "GXLayoutEngine.h"
22 #include "ScriptAndLanguageTags.h"
23 #include "CharSubstitutionFilter.h"
25 #include "LEGlyphStorage.h"
27 #include "OpenTypeUtilities.h"
28 #include "GlyphSubstitutionTables.h"
29 #include "MorphTables.h"
31 #include "DefaultCharMapper.h"
33 #include "KernTable.h"
37 const LEUnicode32
DefaultCharMapper::controlChars
[] = {
38 0x0009, 0x000A, 0x000D,
39 /*0x200C, 0x200D,*/ 0x200E, 0x200F,
40 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
41 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
44 const le_int32
DefaultCharMapper::controlCharsCount
= LE_ARRAY_SIZE(controlChars
);
46 LEUnicode32
DefaultCharMapper::mapChar(LEUnicode32 ch
) const
48 if (fFilterControls
) {
49 le_int32 index
= OpenTypeUtilities::search((le_uint32
)ch
, (le_uint32
*)controlChars
, controlCharsCount
);
51 if (controlChars
[index
] == ch
) {
57 le_int32 index
= OpenTypeUtilities::search((le_uint32
) ch
, (le_uint32
*)DefaultCharMapper::mirroredChars
, DefaultCharMapper::mirroredCharsCount
);
59 if (mirroredChars
[index
] == ch
) {
60 return DefaultCharMapper::srahCderorrim
[index
];
67 // This is here to get it out of LEGlyphFilter.h.
68 // No particular reason to put it here, other than
69 // this is a good central location...
70 LEGlyphFilter::~LEGlyphFilter()
75 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance
*fontInstance
)
76 : fFontInstance(fontInstance
)
81 CharSubstitutionFilter::~CharSubstitutionFilter()
87 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine
)
89 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
91 #define ccmpFeatureMask 0x80000000UL
93 #define canonFeatures (ccmpFeatureMask)
95 static const FeatureMap canonFeatureMap
[] =
97 {ccmpFeatureTag
, ccmpFeatureMask
}
100 static const le_int32 canonFeatureMapCount
= LE_ARRAY_SIZE(canonFeatureMap
);
102 LayoutEngine::LayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, le_int32 typoFlags
)
103 : fGlyphStorage(NULL
), fFontInstance(fontInstance
), fScriptCode(scriptCode
), fLanguageCode(languageCode
),
104 fTypoFlags(typoFlags
)
106 fGlyphStorage
= new LEGlyphStorage();
109 le_int32
LayoutEngine::getGlyphCount() const
111 return fGlyphStorage
->getGlyphCount();
114 void LayoutEngine::getCharIndices(le_int32 charIndices
[], le_int32 indexBase
, LEErrorCode
&success
) const
116 fGlyphStorage
->getCharIndices(charIndices
, indexBase
, success
);
119 void LayoutEngine::getCharIndices(le_int32 charIndices
[], LEErrorCode
&success
) const
121 fGlyphStorage
->getCharIndices(charIndices
, success
);
124 // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
125 void LayoutEngine::getGlyphs(le_uint32 glyphs
[], le_uint32 extraBits
, LEErrorCode
&success
) const
127 fGlyphStorage
->getGlyphs(glyphs
, extraBits
, success
);
130 void LayoutEngine::getGlyphs(LEGlyphID glyphs
[], LEErrorCode
&success
) const
132 fGlyphStorage
->getGlyphs(glyphs
, success
);
136 void LayoutEngine::getGlyphPositions(float positions
[], LEErrorCode
&success
) const
138 fGlyphStorage
->getGlyphPositions(positions
, success
);
141 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex
, float &x
, float &y
, LEErrorCode
&success
) const
143 fGlyphStorage
->getGlyphPosition(glyphIndex
, x
, y
, success
);
146 le_int32
LayoutEngine::characterProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
147 LEUnicode
*&outChars
, LEGlyphStorage
&/*glyphStorage*/, LEErrorCode
&success
)
149 if (LE_FAILURE(success
)) {
153 if (offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
154 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
158 const GlyphSubstitutionTableHeader
*canonGSUBTable
= (GlyphSubstitutionTableHeader
*) CanonShaping::glyphSubstitutionTable
;
159 LETag scriptTag
= OpenTypeLayoutEngine::getScriptTag(fScriptCode
);
160 LETag langSysTag
= OpenTypeLayoutEngine::getLangSysTag(fLanguageCode
);
161 le_int32 i
, dir
= 1, out
= 0, outCharCount
= count
;
163 if (canonGSUBTable
->coversScript(scriptTag
)) {
164 CharSubstitutionFilter
*substitutionFilter
= new CharSubstitutionFilter(fFontInstance
);
165 const LEUnicode
*inChars
= &chars
[offset
];
166 LEUnicode
*reordered
= NULL
;
167 LEGlyphStorage fakeGlyphStorage
;
169 fakeGlyphStorage
.allocateGlyphArray(count
, rightToLeft
, success
);
171 if (LE_FAILURE(success
)) {
175 // This is the cheapest way to get mark reordering only for Hebrew.
176 // We could just do the mark reordering for all scripts, but most
177 // of them probably don't need it...
178 if (fScriptCode
== hebrScriptCode
) {
179 reordered
= LE_NEW_ARRAY(LEUnicode
, count
);
181 if (reordered
== NULL
) {
182 success
= LE_MEMORY_ALLOCATION_ERROR
;
186 CanonShaping::reorderMarks(&chars
[offset
], count
, rightToLeft
, reordered
, fakeGlyphStorage
);
190 fakeGlyphStorage
.allocateAuxData(success
);
192 if (LE_FAILURE(success
)) {
201 for (i
= 0; i
< count
; i
+= 1, out
+= dir
) {
202 fakeGlyphStorage
[out
] = (LEGlyphID
) inChars
[i
];
203 fakeGlyphStorage
.setAuxData(out
, canonFeatures
, success
);
206 if (reordered
!= NULL
) {
207 LE_DELETE_ARRAY(reordered
);
210 outCharCount
= canonGSUBTable
->process(fakeGlyphStorage
, rightToLeft
, scriptTag
, langSysTag
, NULL
, substitutionFilter
, canonFeatureMap
, canonFeatureMapCount
, FALSE
);
212 out
= (rightToLeft
? outCharCount
- 1 : 0);
214 outChars
= LE_NEW_ARRAY(LEUnicode
, outCharCount
);
215 for (i
= 0; i
< outCharCount
; i
+= 1, out
+= dir
) {
216 outChars
[out
] = (LEUnicode
) LE_GET_GLYPH(fakeGlyphStorage
[i
]);
219 delete substitutionFilter
;
225 le_int32
LayoutEngine::computeGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
226 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
228 if (LE_FAILURE(success
)) {
232 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
233 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
237 LEUnicode
*outChars
= NULL
;
238 le_int32 outCharCount
= characterProcessing(chars
, offset
, count
, max
, rightToLeft
, outChars
, glyphStorage
, success
);
240 if (outChars
!= NULL
) {
241 mapCharsToGlyphs(outChars
, 0, outCharCount
, rightToLeft
, rightToLeft
, TRUE
, glyphStorage
, success
);
242 LE_DELETE_ARRAY(outChars
); // FIXME: a subclass may have allocated this, in which case this delete might not work...
244 mapCharsToGlyphs(chars
, offset
, count
, rightToLeft
, rightToLeft
, TRUE
, glyphStorage
, success
);
247 return glyphStorage
.getGlyphCount();
252 void LayoutEngine::positionGlyphs(LEGlyphStorage
&glyphStorage
, float x
, float y
, LEErrorCode
&success
)
254 if (LE_FAILURE(success
)) {
258 glyphStorage
.allocatePositions(success
);
260 if (LE_FAILURE(success
)) {
264 le_int32 i
, glyphCount
= glyphStorage
.getGlyphCount();
266 for (i
= 0; i
< glyphCount
; i
+= 1) {
269 glyphStorage
.setPosition(i
, x
, y
, success
);
271 fFontInstance
->getGlyphAdvance(glyphStorage
[i
], advance
);
276 glyphStorage
.setPosition(glyphCount
, x
, y
, success
);
279 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool
/*reverse*/,
280 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
282 if (LE_FAILURE(success
)) {
286 if (chars
== NULL
|| offset
< 0 || count
< 0) {
287 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
291 if (fTypoFlags
& 0x1) { /* kerning enabled */
292 static const le_uint32 kernTableTag
= LE_KERN_TABLE_TAG
;
294 KernTable
kt(fFontInstance
, getFontTable(kernTableTag
));
295 kt
.process(glyphStorage
);
298 // default is no adjustments
302 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage
&glyphStorage
, LEGlyphFilter
*markFilter
, LEErrorCode
&success
)
305 le_int32 p
, glyphCount
= glyphStorage
.getGlyphCount();
307 if (LE_FAILURE(success
)) {
311 if (markFilter
== NULL
) {
312 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
318 glyphStorage
.getGlyphPosition(0, prev
, ignore
, success
);
320 for (p
= 0; p
< glyphCount
; p
+= 1) {
321 float next
, xAdvance
;
323 glyphStorage
.getGlyphPosition(p
+ 1, next
, ignore
, success
);
325 xAdvance
= next
- prev
;
326 glyphStorage
.adjustPosition(p
, xAdjust
, 0, success
);
328 if (markFilter
->accept(glyphStorage
[p
])) {
335 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, 0, success
);
338 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars
[], le_int32 charCount
, le_bool reverse
, LEGlyphStorage
&glyphStorage
, LEGlyphFilter
*markFilter
, LEErrorCode
&success
)
341 le_int32 c
= 0, direction
= 1, p
;
342 le_int32 glyphCount
= glyphStorage
.getGlyphCount();
344 if (LE_FAILURE(success
)) {
348 if (markFilter
== NULL
) {
349 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
360 glyphStorage
.getGlyphPosition(0, prev
, ignore
, success
);
362 for (p
= 0; p
< charCount
; p
+= 1, c
+= direction
) {
363 float next
, xAdvance
;
365 glyphStorage
.getGlyphPosition(p
+ 1, next
, ignore
, success
);
367 xAdvance
= next
- prev
;
368 glyphStorage
.adjustPosition(p
, xAdjust
, 0, success
);
370 if (markFilter
->accept(chars
[c
])) {
377 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, 0, success
);
380 const void *LayoutEngine::getFontTable(LETag tableTag
) const
382 return fFontInstance
->getFontTable(tableTag
);
385 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
, le_bool mirror
, le_bool filterZeroWidth
,
386 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
388 if (LE_FAILURE(success
)) {
392 glyphStorage
.allocateGlyphArray(count
, reverse
, success
);
394 DefaultCharMapper
charMapper(TRUE
, mirror
);
396 fFontInstance
->mapCharsToGlyphs(chars
, offset
, count
, reverse
, &charMapper
, filterZeroWidth
, glyphStorage
);
399 // Input: characters, font?
400 // Output: glyphs, positions, char indices
401 // Returns: number of glyphs
402 le_int32
LayoutEngine::layoutChars(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
403 float x
, float y
, LEErrorCode
&success
)
405 if (LE_FAILURE(success
)) {
409 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
410 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
416 if (fGlyphStorage
->getGlyphCount() > 0) {
417 fGlyphStorage
->reset();
420 glyphCount
= computeGlyphs(chars
, offset
, count
, max
, rightToLeft
, *fGlyphStorage
, success
);
421 positionGlyphs(*fGlyphStorage
, x
, y
, success
);
422 adjustGlyphPositions(chars
, offset
, count
, rightToLeft
, *fGlyphStorage
, success
);
427 void LayoutEngine::reset()
429 fGlyphStorage
->reset();
432 LayoutEngine
*LayoutEngine::layoutEngineFactory(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, LEErrorCode
&success
)
434 // 3 -> kerning and ligatures
435 return LayoutEngine::layoutEngineFactory(fontInstance
, scriptCode
, languageCode
, 3, success
);
438 LayoutEngine
*LayoutEngine::layoutEngineFactory(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, le_int32 typoFlags
, LEErrorCode
&success
)
440 static const le_uint32 gsubTableTag
= LE_GSUB_TABLE_TAG
;
441 static const le_uint32 mortTableTag
= LE_MORT_TABLE_TAG
;
443 if (LE_FAILURE(success
)) {
447 const GlyphSubstitutionTableHeader
*gsubTable
= (const GlyphSubstitutionTableHeader
*) fontInstance
->getFontTable(gsubTableTag
);
448 LayoutEngine
*result
= NULL
;
449 LETag scriptTag
= 0x00000000;
450 LETag languageTag
= 0x00000000;
452 if (gsubTable
!= NULL
&& gsubTable
->coversScript(scriptTag
= OpenTypeLayoutEngine::getScriptTag(scriptCode
))) {
453 switch (scriptCode
) {
464 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
468 result
= new ArabicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
472 result
= new HangulOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
476 languageTag
= OpenTypeLayoutEngine::getLangSysTag(languageCode
);
478 switch (languageCode
) {
479 case korLanguageCode
:
480 case janLanguageCode
:
481 case zhtLanguageCode
:
482 case zhsLanguageCode
:
483 if (gsubTable
->coversScriptAndLanguage(scriptTag
, languageTag
, TRUE
)) {
484 result
= new HanOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
488 // note: falling through to default case.
490 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
497 result
= new TibetanOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
501 result
= new KhmerOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
505 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
509 const MorphTableHeader
*morphTable
= (MorphTableHeader
*) fontInstance
->getFontTable(mortTableTag
);
511 if (morphTable
!= NULL
) {
512 result
= new GXLayoutEngine(fontInstance
, scriptCode
, languageCode
, morphTable
);
514 switch (scriptCode
) {
526 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
);
531 //case hebrScriptCode:
532 result
= new UnicodeArabicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
);
535 //case hebrScriptCode:
536 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
539 result
= new ThaiLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
);
543 result
= new LayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
);
549 if (result
== NULL
) {
550 success
= LE_MEMORY_ALLOCATION_ERROR
;
556 LayoutEngine::~LayoutEngine() {
557 delete fGlyphStorage
;