4 * (C) Copyright IBM Corp. 1998-2008 - 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 "GlyphDefinitionTables.h"
30 #include "MorphTables.h"
32 #include "DefaultCharMapper.h"
34 #include "KernTable.h"
38 /* Leave this copyright notice here! It needs to go somewhere in this library. */
39 static const char copyright
[] = U_COPYRIGHT_STRING
;
41 const LEUnicode32
DefaultCharMapper::controlChars
[] = {
42 0x0009, 0x000A, 0x000D,
43 /*0x200C, 0x200D,*/ 0x200E, 0x200F,
44 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
45 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
48 const le_int32
DefaultCharMapper::controlCharsCount
= LE_ARRAY_SIZE(controlChars
);
50 LEUnicode32
DefaultCharMapper::mapChar(LEUnicode32 ch
) const
52 if (fFilterControls
) {
53 le_int32 index
= OpenTypeUtilities::search((le_uint32
)ch
, (le_uint32
*)controlChars
, controlCharsCount
);
55 if (controlChars
[index
] == ch
) {
61 le_int32 index
= OpenTypeUtilities::search((le_uint32
) ch
, (le_uint32
*)DefaultCharMapper::mirroredChars
, DefaultCharMapper::mirroredCharsCount
);
63 if (mirroredChars
[index
] == ch
) {
64 return DefaultCharMapper::srahCderorrim
[index
];
71 // This is here to get it out of LEGlyphFilter.h.
72 // No particular reason to put it here, other than
73 // this is a good central location...
74 LEGlyphFilter::~LEGlyphFilter()
79 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance
*fontInstance
)
80 : fFontInstance(fontInstance
)
85 CharSubstitutionFilter::~CharSubstitutionFilter()
90 class CanonMarkFilter
: public UMemory
, public LEGlyphFilter
93 const GlyphClassDefinitionTable
*classDefTable
;
95 CanonMarkFilter(const CanonMarkFilter
&other
); // forbid copying of this class
96 CanonMarkFilter
&operator=(const CanonMarkFilter
&other
); // forbid copying of this class
99 CanonMarkFilter(const GlyphDefinitionTableHeader
*gdefTable
);
100 virtual ~CanonMarkFilter();
102 virtual le_bool
accept(LEGlyphID glyph
) const;
105 CanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader
*gdefTable
)
107 classDefTable
= gdefTable
->getMarkAttachClassDefinitionTable();
110 CanonMarkFilter::~CanonMarkFilter()
115 le_bool
CanonMarkFilter::accept(LEGlyphID glyph
) const
117 le_int32 glyphClass
= classDefTable
->getGlyphClass(glyph
);
119 return glyphClass
!= 0;
122 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine
)
124 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
126 #define ccmpFeatureMask 0x80000000UL
128 #define canonFeatures (ccmpFeatureMask)
130 static const FeatureMap canonFeatureMap
[] =
132 {ccmpFeatureTag
, ccmpFeatureMask
}
135 static const le_int32 canonFeatureMapCount
= LE_ARRAY_SIZE(canonFeatureMap
);
137 LayoutEngine::LayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, le_int32 typoFlags
)
138 : fGlyphStorage(NULL
), fFontInstance(fontInstance
), fScriptCode(scriptCode
), fLanguageCode(languageCode
),
139 fTypoFlags(typoFlags
), fFilterZeroWidth(TRUE
)
141 fGlyphStorage
= new LEGlyphStorage();
144 le_int32
LayoutEngine::getGlyphCount() const
146 return fGlyphStorage
->getGlyphCount();
149 void LayoutEngine::getCharIndices(le_int32 charIndices
[], le_int32 indexBase
, LEErrorCode
&success
) const
151 fGlyphStorage
->getCharIndices(charIndices
, indexBase
, success
);
154 void LayoutEngine::getCharIndices(le_int32 charIndices
[], LEErrorCode
&success
) const
156 fGlyphStorage
->getCharIndices(charIndices
, success
);
159 // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
160 void LayoutEngine::getGlyphs(le_uint32 glyphs
[], le_uint32 extraBits
, LEErrorCode
&success
) const
162 fGlyphStorage
->getGlyphs(glyphs
, extraBits
, success
);
165 void LayoutEngine::getGlyphs(LEGlyphID glyphs
[], LEErrorCode
&success
) const
167 fGlyphStorage
->getGlyphs(glyphs
, success
);
171 void LayoutEngine::getGlyphPositions(float positions
[], LEErrorCode
&success
) const
173 fGlyphStorage
->getGlyphPositions(positions
, success
);
176 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex
, float &x
, float &y
, LEErrorCode
&success
) const
178 fGlyphStorage
->getGlyphPosition(glyphIndex
, x
, y
, success
);
181 le_int32
LayoutEngine::characterProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
182 LEUnicode
*&outChars
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
184 if (LE_FAILURE(success
)) {
188 if (offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
189 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
193 const GlyphSubstitutionTableHeader
*canonGSUBTable
= (GlyphSubstitutionTableHeader
*) CanonShaping::glyphSubstitutionTable
;
194 LETag scriptTag
= OpenTypeLayoutEngine::getScriptTag(fScriptCode
);
195 LETag langSysTag
= OpenTypeLayoutEngine::getLangSysTag(fLanguageCode
);
196 le_int32 i
, dir
= 1, out
= 0, outCharCount
= count
;
198 if (canonGSUBTable
->coversScript(scriptTag
)) {
199 CharSubstitutionFilter
*substitutionFilter
= new CharSubstitutionFilter(fFontInstance
);
200 const LEUnicode
*inChars
= &chars
[offset
];
201 LEUnicode
*reordered
= NULL
;
202 LEGlyphStorage fakeGlyphStorage
;
204 fakeGlyphStorage
.allocateGlyphArray(count
, rightToLeft
, success
);
206 if (LE_FAILURE(success
)) {
210 // This is the cheapest way to get mark reordering only for Hebrew.
211 // We could just do the mark reordering for all scripts, but most
212 // of them probably don't need it...
213 if (fScriptCode
== hebrScriptCode
) {
214 reordered
= LE_NEW_ARRAY(LEUnicode
, count
);
216 if (reordered
== NULL
) {
217 success
= LE_MEMORY_ALLOCATION_ERROR
;
221 CanonShaping::reorderMarks(&chars
[offset
], count
, rightToLeft
, reordered
, fakeGlyphStorage
);
225 fakeGlyphStorage
.allocateAuxData(success
);
227 if (LE_FAILURE(success
)) {
236 for (i
= 0; i
< count
; i
+= 1, out
+= dir
) {
237 fakeGlyphStorage
[out
] = (LEGlyphID
) inChars
[i
];
238 fakeGlyphStorage
.setAuxData(out
, canonFeatures
, success
);
241 if (reordered
!= NULL
) {
242 LE_DELETE_ARRAY(reordered
);
245 outCharCount
= canonGSUBTable
->process(fakeGlyphStorage
, rightToLeft
, scriptTag
, langSysTag
, NULL
, substitutionFilter
, canonFeatureMap
, canonFeatureMapCount
, FALSE
);
247 out
= (rightToLeft
? outCharCount
- 1 : 0);
250 * The char indices array in fakeGlyphStorage has the correct mapping
251 * back to the original input characters. Save it in glyphStorage. The
252 * subsequent call to glyphStoratge.allocateGlyphArray will keep this
253 * array rather than allocating and initializing a new one.
255 glyphStorage
.adoptCharIndicesArray(fakeGlyphStorage
);
257 outChars
= LE_NEW_ARRAY(LEUnicode
, outCharCount
);
258 for (i
= 0; i
< outCharCount
; i
+= 1, out
+= dir
) {
259 outChars
[out
] = (LEUnicode
) LE_GET_GLYPH(fakeGlyphStorage
[i
]);
262 delete substitutionFilter
;
268 le_int32
LayoutEngine::computeGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
269 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
271 if (LE_FAILURE(success
)) {
275 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
276 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
280 LEUnicode
*outChars
= NULL
;
281 le_int32 outCharCount
= characterProcessing(chars
, offset
, count
, max
, rightToLeft
, outChars
, glyphStorage
, success
);
283 if (outChars
!= NULL
) {
284 mapCharsToGlyphs(outChars
, 0, outCharCount
, rightToLeft
, rightToLeft
, glyphStorage
, success
);
285 LE_DELETE_ARRAY(outChars
); // FIXME: a subclass may have allocated this, in which case this delete might not work...
287 mapCharsToGlyphs(chars
, offset
, count
, rightToLeft
, rightToLeft
, glyphStorage
, success
);
290 return glyphStorage
.getGlyphCount();
295 void LayoutEngine::positionGlyphs(LEGlyphStorage
&glyphStorage
, float x
, float y
, LEErrorCode
&success
)
297 if (LE_FAILURE(success
)) {
301 glyphStorage
.allocatePositions(success
);
303 if (LE_FAILURE(success
)) {
307 le_int32 i
, glyphCount
= glyphStorage
.getGlyphCount();
309 for (i
= 0; i
< glyphCount
; i
+= 1) {
312 glyphStorage
.setPosition(i
, x
, y
, success
);
314 fFontInstance
->getGlyphAdvance(glyphStorage
[i
], advance
);
319 glyphStorage
.setPosition(glyphCount
, x
, y
, success
);
322 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
,
323 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
325 if (LE_FAILURE(success
)) {
329 if (chars
== NULL
|| offset
< 0 || count
< 0) {
330 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
334 GlyphDefinitionTableHeader
*gdefTable
= (GlyphDefinitionTableHeader
*) CanonShaping::glyphDefinitionTable
;
335 CanonMarkFilter
filter(gdefTable
);
337 adjustMarkGlyphs(&chars
[offset
], count
, reverse
, glyphStorage
, &filter
, success
);
339 if (fTypoFlags
& 0x1) { /* kerning enabled */
340 static const le_uint32 kernTableTag
= LE_KERN_TABLE_TAG
;
342 KernTable
kt(fFontInstance
, getFontTable(kernTableTag
));
343 kt
.process(glyphStorage
);
346 // default is no adjustments
350 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage
&glyphStorage
, LEGlyphFilter
*markFilter
, LEErrorCode
&success
)
353 le_int32 p
, glyphCount
= glyphStorage
.getGlyphCount();
355 if (LE_FAILURE(success
)) {
359 if (markFilter
== NULL
) {
360 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
366 glyphStorage
.getGlyphPosition(0, prev
, ignore
, success
);
368 for (p
= 0; p
< glyphCount
; p
+= 1) {
369 float next
, xAdvance
;
371 glyphStorage
.getGlyphPosition(p
+ 1, next
, ignore
, success
);
373 xAdvance
= next
- prev
;
374 glyphStorage
.adjustPosition(p
, xAdjust
, 0, success
);
376 if (markFilter
->accept(glyphStorage
[p
])) {
383 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, 0, success
);
386 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars
[], le_int32 charCount
, le_bool reverse
, LEGlyphStorage
&glyphStorage
, LEGlyphFilter
*markFilter
, LEErrorCode
&success
)
389 le_int32 c
= 0, direction
= 1, p
;
390 le_int32 glyphCount
= glyphStorage
.getGlyphCount();
392 if (LE_FAILURE(success
)) {
396 if (markFilter
== NULL
) {
397 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
408 glyphStorage
.getGlyphPosition(0, prev
, ignore
, success
);
410 for (p
= 0; p
< charCount
; p
+= 1, c
+= direction
) {
411 float next
, xAdvance
;
413 glyphStorage
.getGlyphPosition(p
+ 1, next
, ignore
, success
);
415 xAdvance
= next
- prev
;
416 glyphStorage
.adjustPosition(p
, xAdjust
, 0, success
);
418 if (markFilter
->accept(chars
[c
])) {
425 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, 0, success
);
428 const void *LayoutEngine::getFontTable(LETag tableTag
) const
430 return fFontInstance
->getFontTable(tableTag
);
433 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
, le_bool mirror
,
434 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
436 if (LE_FAILURE(success
)) {
440 glyphStorage
.allocateGlyphArray(count
, reverse
, success
);
442 DefaultCharMapper
charMapper(TRUE
, mirror
);
444 fFontInstance
->mapCharsToGlyphs(chars
, offset
, count
, reverse
, &charMapper
, fFilterZeroWidth
, glyphStorage
);
447 // Input: characters, font?
448 // Output: glyphs, positions, char indices
449 // Returns: number of glyphs
450 le_int32
LayoutEngine::layoutChars(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
451 float x
, float y
, LEErrorCode
&success
)
453 if (LE_FAILURE(success
)) {
457 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
458 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
464 if (fGlyphStorage
->getGlyphCount() > 0) {
465 fGlyphStorage
->reset();
468 glyphCount
= computeGlyphs(chars
, offset
, count
, max
, rightToLeft
, *fGlyphStorage
, success
);
469 positionGlyphs(*fGlyphStorage
, x
, y
, success
);
470 adjustGlyphPositions(chars
, offset
, count
, rightToLeft
, *fGlyphStorage
, success
);
475 void LayoutEngine::reset()
477 fGlyphStorage
->reset();
480 LayoutEngine
*LayoutEngine::layoutEngineFactory(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, LEErrorCode
&success
)
482 // 3 -> kerning and ligatures
483 return LayoutEngine::layoutEngineFactory(fontInstance
, scriptCode
, languageCode
, 3, success
);
486 LayoutEngine
*LayoutEngine::layoutEngineFactory(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, le_int32 typoFlags
, LEErrorCode
&success
)
488 static const le_uint32 gsubTableTag
= LE_GSUB_TABLE_TAG
;
489 static const le_uint32 mortTableTag
= LE_MORT_TABLE_TAG
;
491 if (LE_FAILURE(success
)) {
495 const GlyphSubstitutionTableHeader
*gsubTable
= (const GlyphSubstitutionTableHeader
*) fontInstance
->getFontTable(gsubTableTag
);
496 LayoutEngine
*result
= NULL
;
497 LETag scriptTag
= 0x00000000;
498 LETag languageTag
= 0x00000000;
500 if (gsubTable
!= NULL
&& gsubTable
->coversScript(scriptTag
= OpenTypeLayoutEngine::getScriptTag(scriptCode
))) {
501 switch (scriptCode
) {
512 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
516 result
= new ArabicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
520 result
= new HangulOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
524 languageTag
= OpenTypeLayoutEngine::getLangSysTag(languageCode
);
526 switch (languageCode
) {
527 case korLanguageCode
:
528 case janLanguageCode
:
529 case zhtLanguageCode
:
530 case zhsLanguageCode
:
531 if (gsubTable
->coversScriptAndLanguage(scriptTag
, languageTag
, TRUE
)) {
532 result
= new HanOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
536 // note: falling through to default case.
538 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
545 result
= new TibetanOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
549 result
= new KhmerOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
553 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
);
557 const MorphTableHeader
*morphTable
= (MorphTableHeader
*) fontInstance
->getFontTable(mortTableTag
);
559 if (morphTable
!= NULL
) {
560 result
= new GXLayoutEngine(fontInstance
, scriptCode
, languageCode
, morphTable
);
562 switch (scriptCode
) {
574 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
);
579 //case hebrScriptCode:
580 result
= new UnicodeArabicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
);
583 //case hebrScriptCode:
584 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
587 result
= new ThaiLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
);
591 result
= new HangulOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
);
595 result
= new LayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
);
601 if (result
== NULL
) {
602 success
= LE_MEMORY_ALLOCATION_ERROR
;
608 LayoutEngine::~LayoutEngine() {
609 delete fGlyphStorage
;