2 * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved
7 #include "LELanguages.h"
10 #include "LayoutEngine.h"
11 #include "ArabicLayoutEngine.h"
12 #include "CanonShaping.h"
13 #include "HanLayoutEngine.h"
14 #include "HangulLayoutEngine.h"
15 #include "IndicLayoutEngine.h"
16 #include "KhmerLayoutEngine.h"
17 #include "ThaiLayoutEngine.h"
18 #include "TibetanLayoutEngine.h"
19 #include "GXLayoutEngine.h"
20 #include "GXLayoutEngine2.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 /* TODO: remove these? */
42 const le_int32
LayoutEngine::kTypoFlagKern
= LE_Kerning_FEATURE_FLAG
;
43 const le_int32
LayoutEngine::kTypoFlagLiga
= LE_Ligatures_FEATURE_FLAG
;
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
52 const le_int32
DefaultCharMapper::controlCharsCount
= LE_ARRAY_SIZE(controlChars
);
54 LEUnicode32
DefaultCharMapper::mapChar(LEUnicode32 ch
) const
56 if (fFilterControls
) {
57 le_int32 index
= OpenTypeUtilities::search((le_uint32
)ch
, (le_uint32
*)controlChars
, controlCharsCount
);
59 if (controlChars
[index
] == ch
) {
65 le_int32 index
= OpenTypeUtilities::search((le_uint32
) ch
, (le_uint32
*)DefaultCharMapper::mirroredChars
, DefaultCharMapper::mirroredCharsCount
);
67 if (mirroredChars
[index
] == ch
) {
68 return DefaultCharMapper::srahCderorrim
[index
];
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()
83 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance
*fontInstance
)
84 : fFontInstance(fontInstance
)
89 CharSubstitutionFilter::~CharSubstitutionFilter()
94 class CanonMarkFilter
: public UMemory
, public LEGlyphFilter
97 const GlyphClassDefinitionTable
*classDefTable
;
99 CanonMarkFilter(const CanonMarkFilter
&other
); // forbid copying of this class
100 CanonMarkFilter
&operator=(const CanonMarkFilter
&other
); // forbid copying of this class
103 CanonMarkFilter(const GlyphDefinitionTableHeader
*gdefTable
);
104 virtual ~CanonMarkFilter();
106 virtual le_bool
accept(LEGlyphID glyph
) const;
109 CanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader
*gdefTable
)
111 classDefTable
= gdefTable
->getMarkAttachClassDefinitionTable();
114 CanonMarkFilter::~CanonMarkFilter()
119 le_bool
CanonMarkFilter::accept(LEGlyphID glyph
) const
121 le_int32 glyphClass
= classDefTable
->getGlyphClass(glyph
);
123 return glyphClass
!= 0;
126 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine
)
128 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
130 #define ccmpFeatureMask 0x80000000UL
132 #define canonFeatures (ccmpFeatureMask)
134 static const FeatureMap canonFeatureMap
[] =
136 {ccmpFeatureTag
, ccmpFeatureMask
}
139 static const le_int32 canonFeatureMapCount
= LE_ARRAY_SIZE(canonFeatureMap
);
141 LayoutEngine::LayoutEngine(const LEFontInstance
*fontInstance
,
143 le_int32 languageCode
,
145 LEErrorCode
&success
)
146 : fGlyphStorage(NULL
), fFontInstance(fontInstance
), fScriptCode(scriptCode
), fLanguageCode(languageCode
),
147 fTypoFlags(typoFlags
), fFilterZeroWidth(TRUE
)
149 if (LE_FAILURE(success
)) {
153 fGlyphStorage
= new LEGlyphStorage();
154 if (fGlyphStorage
== NULL
) {
155 success
= LE_MEMORY_ALLOCATION_ERROR
;
159 le_int32
LayoutEngine::getGlyphCount() const
161 return fGlyphStorage
->getGlyphCount();
164 void LayoutEngine::getCharIndices(le_int32 charIndices
[], le_int32 indexBase
, LEErrorCode
&success
) const
166 fGlyphStorage
->getCharIndices(charIndices
, indexBase
, success
);
169 void LayoutEngine::getCharIndices(le_int32 charIndices
[], LEErrorCode
&success
) const
171 fGlyphStorage
->getCharIndices(charIndices
, success
);
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
177 fGlyphStorage
->getGlyphs(glyphs
, extraBits
, success
);
180 void LayoutEngine::getGlyphs(LEGlyphID glyphs
[], LEErrorCode
&success
) const
182 fGlyphStorage
->getGlyphs(glyphs
, success
);
186 void LayoutEngine::getGlyphPositions(float positions
[], LEErrorCode
&success
) const
188 fGlyphStorage
->getGlyphPositions(positions
, success
);
191 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex
, float &x
, float &y
, LEErrorCode
&success
) const
193 fGlyphStorage
->getGlyphPosition(glyphIndex
, x
, y
, success
);
196 le_int32
LayoutEngine::characterProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
197 LEUnicode
*&outChars
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
199 if (LE_FAILURE(success
)) {
203 if (offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
204 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
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
;
213 if (canonGSUBTable
->coversScript(scriptTag
)) {
214 CharSubstitutionFilter
*substitutionFilter
= new CharSubstitutionFilter(fFontInstance
);
215 if (substitutionFilter
== NULL
) {
216 success
= LE_MEMORY_ALLOCATION_ERROR
;
220 const LEUnicode
*inChars
= &chars
[offset
];
221 LEUnicode
*reordered
= NULL
;
222 LEGlyphStorage fakeGlyphStorage
;
224 fakeGlyphStorage
.allocateGlyphArray(count
, rightToLeft
, success
);
226 if (LE_FAILURE(success
)) {
227 delete substitutionFilter
;
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
);
237 if (reordered
== NULL
) {
238 delete substitutionFilter
;
239 success
= LE_MEMORY_ALLOCATION_ERROR
;
243 CanonShaping::reorderMarks(&chars
[offset
], count
, rightToLeft
, reordered
, fakeGlyphStorage
);
247 fakeGlyphStorage
.allocateAuxData(success
);
249 if (LE_FAILURE(success
)) {
250 delete substitutionFilter
;
259 for (i
= 0; i
< count
; i
+= 1, out
+= dir
) {
260 fakeGlyphStorage
[out
] = (LEGlyphID
) inChars
[i
];
261 fakeGlyphStorage
.setAuxData(out
, canonFeatures
, success
);
264 if (reordered
!= NULL
) {
265 LE_DELETE_ARRAY(reordered
);
268 outCharCount
= canonGSUBTable
->process(fakeGlyphStorage
, rightToLeft
, scriptTag
, langSysTag
, NULL
, substitutionFilter
, canonFeatureMap
, canonFeatureMapCount
, FALSE
, success
);
270 if (LE_FAILURE(success
)) {
271 delete substitutionFilter
;
275 out
= (rightToLeft
? outCharCount
- 1 : 0);
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.
283 glyphStorage
.adoptCharIndicesArray(fakeGlyphStorage
);
285 outChars
= LE_NEW_ARRAY(LEUnicode
, outCharCount
);
287 if (outChars
== NULL
) {
288 delete substitutionFilter
;
289 success
= LE_MEMORY_ALLOCATION_ERROR
;
293 for (i
= 0; i
< outCharCount
; i
+= 1, out
+= dir
) {
294 outChars
[out
] = (LEUnicode
) LE_GET_GLYPH(fakeGlyphStorage
[i
]);
297 delete substitutionFilter
;
303 le_int32
LayoutEngine::computeGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
304 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
306 if (LE_FAILURE(success
)) {
310 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
311 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
315 LEUnicode
*outChars
= NULL
;
316 le_int32 outCharCount
= characterProcessing(chars
, offset
, count
, max
, rightToLeft
, outChars
, glyphStorage
, success
);
318 if (outChars
!= NULL
) {
319 mapCharsToGlyphs(outChars
, 0, outCharCount
, rightToLeft
, rightToLeft
, glyphStorage
, success
);
320 LE_DELETE_ARRAY(outChars
); // FIXME: a subclass may have allocated this, in which case this delete might not work...
322 mapCharsToGlyphs(chars
, offset
, count
, rightToLeft
, rightToLeft
, glyphStorage
, success
);
325 return glyphStorage
.getGlyphCount();
330 void LayoutEngine::positionGlyphs(LEGlyphStorage
&glyphStorage
, float x
, float y
, LEErrorCode
&success
)
332 if (LE_FAILURE(success
)) {
336 glyphStorage
.allocatePositions(success
);
338 if (LE_FAILURE(success
)) {
342 le_int32 i
, glyphCount
= glyphStorage
.getGlyphCount();
344 for (i
= 0; i
< glyphCount
; i
+= 1) {
347 glyphStorage
.setPosition(i
, x
, y
, success
);
349 fFontInstance
->getGlyphAdvance(glyphStorage
[i
], advance
);
354 glyphStorage
.setPosition(glyphCount
, x
, y
, success
);
357 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
,
358 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
360 if (LE_FAILURE(success
)) {
364 if (chars
== NULL
|| offset
< 0 || count
< 0) {
365 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
369 GlyphDefinitionTableHeader
*gdefTable
= (GlyphDefinitionTableHeader
*) CanonShaping::glyphDefinitionTable
;
370 CanonMarkFilter
filter(gdefTable
);
372 adjustMarkGlyphs(&chars
[offset
], count
, reverse
, glyphStorage
, &filter
, success
);
374 if (fTypoFlags
& 0x1) { /* kerning enabled */
375 static const le_uint32 kernTableTag
= LE_KERN_TABLE_TAG
;
377 KernTable
kt(fFontInstance
, getFontTable(kernTableTag
));
378 kt
.process(glyphStorage
);
381 // default is no adjustments
385 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage
&glyphStorage
, LEGlyphFilter
*markFilter
, LEErrorCode
&success
)
388 le_int32 p
, glyphCount
= glyphStorage
.getGlyphCount();
390 if (LE_FAILURE(success
)) {
394 if (markFilter
== NULL
) {
395 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
401 glyphStorage
.getGlyphPosition(0, prev
, ignore
, success
);
403 for (p
= 0; p
< glyphCount
; p
+= 1) {
404 float next
, xAdvance
;
406 glyphStorage
.getGlyphPosition(p
+ 1, next
, ignore
, success
);
408 xAdvance
= next
- prev
;
409 glyphStorage
.adjustPosition(p
, xAdjust
, 0, success
);
411 if (markFilter
->accept(glyphStorage
[p
])) {
418 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, 0, success
);
421 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars
[], le_int32 charCount
, le_bool reverse
, LEGlyphStorage
&glyphStorage
, LEGlyphFilter
*markFilter
, LEErrorCode
&success
)
424 le_int32 c
= 0, direction
= 1, p
;
425 le_int32 glyphCount
= glyphStorage
.getGlyphCount();
427 if (LE_FAILURE(success
)) {
431 if (markFilter
== NULL
) {
432 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
443 glyphStorage
.getGlyphPosition(0, prev
, ignore
, success
);
445 for (p
= 0; p
< charCount
; p
+= 1, c
+= direction
) {
446 float next
, xAdvance
;
448 glyphStorage
.getGlyphPosition(p
+ 1, next
, ignore
, success
);
450 xAdvance
= next
- prev
;
451 glyphStorage
.adjustPosition(p
, xAdjust
, 0, success
);
453 if (markFilter
->accept(chars
[c
])) {
460 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, 0, success
);
463 const void *LayoutEngine::getFontTable(LETag tableTag
) const
465 return fFontInstance
->getFontTable(tableTag
);
468 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
, le_bool mirror
,
469 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
471 if (LE_FAILURE(success
)) {
475 glyphStorage
.allocateGlyphArray(count
, reverse
, success
);
477 DefaultCharMapper
charMapper(TRUE
, mirror
);
479 fFontInstance
->mapCharsToGlyphs(chars
, offset
, count
, reverse
, &charMapper
, fFilterZeroWidth
, glyphStorage
);
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
)
488 if (LE_FAILURE(success
)) {
492 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
493 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
499 if (fGlyphStorage
->getGlyphCount() > 0) {
500 fGlyphStorage
->reset();
503 glyphCount
= computeGlyphs(chars
, offset
, count
, max
, rightToLeft
, *fGlyphStorage
, success
);
504 positionGlyphs(*fGlyphStorage
, x
, y
, success
);
505 adjustGlyphPositions(chars
, offset
, count
, rightToLeft
, *fGlyphStorage
, success
);
510 void LayoutEngine::reset()
512 fGlyphStorage
->reset();
515 LayoutEngine
*LayoutEngine::layoutEngineFactory(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, LEErrorCode
&success
)
517 // 3 -> kerning and ligatures
518 return LayoutEngine::layoutEngineFactory(fontInstance
, scriptCode
, languageCode
, 3, success
);
521 LayoutEngine
*LayoutEngine::layoutEngineFactory(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, le_int32 typoFlags
, LEErrorCode
&success
)
523 static const le_uint32 gsubTableTag
= LE_GSUB_TABLE_TAG
;
524 static const le_uint32 mortTableTag
= LE_MORT_TABLE_TAG
;
525 static const le_uint32 morxTableTag
= LE_MORX_TABLE_TAG
;
527 if (LE_FAILURE(success
)) {
531 const GlyphSubstitutionTableHeader
*gsubTable
= (const GlyphSubstitutionTableHeader
*) fontInstance
->getFontTable(gsubTableTag
);
532 LayoutEngine
*result
= NULL
;
533 LETag scriptTag
= 0x00000000;
534 LETag languageTag
= 0x00000000;
535 LETag v2ScriptTag
= OpenTypeLayoutEngine::getV2ScriptTag(scriptCode
);
537 // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are
540 if ( v2ScriptTag
== dev2ScriptTag
&& gsubTable
!= NULL
&& gsubTable
->coversScript( v2ScriptTag
)) {
541 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, TRUE
, gsubTable
, success
);
543 else if (gsubTable
!= NULL
&& gsubTable
->coversScript(scriptTag
= OpenTypeLayoutEngine::getScriptTag(scriptCode
))) {
544 switch (scriptCode
) {
555 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, FALSE
, gsubTable
, success
);
559 result
= new ArabicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
563 // Disable hebrew ligatures since they have only archaic uses, see ticket #8318
564 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
& ~kTypoFlagLiga
, gsubTable
, success
);
568 result
= new HangulOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
572 languageTag
= OpenTypeLayoutEngine::getLangSysTag(languageCode
);
574 switch (languageCode
) {
575 case korLanguageCode
:
576 case janLanguageCode
:
577 case zhtLanguageCode
:
578 case zhsLanguageCode
:
579 if (gsubTable
->coversScriptAndLanguage(scriptTag
, languageTag
, TRUE
)) {
580 result
= new HanOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
584 // note: falling through to default case.
586 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
593 result
= new TibetanOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
597 result
= new KhmerOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
601 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
605 MorphTableHeader2
*morxTable
= (MorphTableHeader2
*)fontInstance
->getFontTable(morxTableTag
);
606 if (morxTable
!= NULL
) {
607 result
= new GXLayoutEngine2(fontInstance
, scriptCode
, languageCode
, morxTable
, typoFlags
, success
);
609 const MorphTableHeader
*mortTable
= (MorphTableHeader
*) fontInstance
->getFontTable(mortTableTag
);
610 if (mortTable
!= NULL
) { // mort
611 result
= new GXLayoutEngine(fontInstance
, scriptCode
, languageCode
, mortTable
, success
);
613 switch (scriptCode
) {
625 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, success
);
630 //case hebrScriptCode:
631 result
= new UnicodeArabicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, success
);
634 //case hebrScriptCode:
635 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
638 result
= new ThaiLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, success
);
642 result
= new HangulOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, success
);
646 result
= new LayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, success
);
653 if (result
&& LE_FAILURE(success
)) {
658 if (result
== NULL
) {
659 success
= LE_MEMORY_ALLOCATION_ERROR
;
665 LayoutEngine::~LayoutEngine() {
666 delete fGlyphStorage
;