2 * (C) Copyright IBM Corp. and others 1998-2014 - 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 (void)copyright
; // Suppress unused variable warning.
57 if (fFilterControls
) {
58 le_int32 index
= OpenTypeUtilities::search((le_uint32
)ch
, (le_uint32
*)controlChars
, controlCharsCount
);
60 if (controlChars
[index
] == ch
) {
66 le_int32 index
= OpenTypeUtilities::search((le_uint32
) ch
, (le_uint32
*)DefaultCharMapper::mirroredChars
, DefaultCharMapper::mirroredCharsCount
);
68 if (mirroredChars
[index
] == ch
) {
69 return DefaultCharMapper::srahCderorrim
[index
];
76 // This is here to get it out of LEGlyphFilter.h.
77 // No particular reason to put it here, other than
78 // this is a good central location...
79 LEGlyphFilter::~LEGlyphFilter()
84 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance
*fontInstance
)
85 : fFontInstance(fontInstance
)
90 CharSubstitutionFilter::~CharSubstitutionFilter()
95 class CanonMarkFilter
: public UMemory
, public LEGlyphFilter
98 const LEReferenceTo
<GlyphClassDefinitionTable
> classDefTable
;
100 CanonMarkFilter(const CanonMarkFilter
&other
); // forbid copying of this class
101 CanonMarkFilter
&operator=(const CanonMarkFilter
&other
); // forbid copying of this class
104 CanonMarkFilter(const LEReferenceTo
<GlyphDefinitionTableHeader
> &gdefTable
, LEErrorCode
&success
);
105 virtual ~CanonMarkFilter();
107 virtual le_bool
accept(LEGlyphID glyph
) const;
110 CanonMarkFilter::CanonMarkFilter(const LEReferenceTo
<GlyphDefinitionTableHeader
> &gdefTable
, LEErrorCode
&success
)
111 : classDefTable(gdefTable
->getMarkAttachClassDefinitionTable(gdefTable
, success
))
115 CanonMarkFilter::~CanonMarkFilter()
120 le_bool
CanonMarkFilter::accept(LEGlyphID glyph
) const
122 LEErrorCode success
= LE_NO_ERROR
;
123 le_int32 glyphClass
= classDefTable
->getGlyphClass(classDefTable
, glyph
, success
);
124 if(LE_FAILURE(success
)) return false;
125 return glyphClass
!= 0;
128 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine
)
130 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
132 #define ccmpFeatureMask 0x80000000UL
134 #define canonFeatures (ccmpFeatureMask)
136 static const FeatureMap canonFeatureMap
[] =
138 {ccmpFeatureTag
, ccmpFeatureMask
}
141 static const le_int32 canonFeatureMapCount
= LE_ARRAY_SIZE(canonFeatureMap
);
143 LayoutEngine::LayoutEngine(const LEFontInstance
*fontInstance
,
145 le_int32 languageCode
,
147 LEErrorCode
&success
)
148 : fGlyphStorage(NULL
), fFontInstance(fontInstance
), fScriptCode(scriptCode
), fLanguageCode(languageCode
),
149 fTypoFlags(typoFlags
), fFilterZeroWidth(TRUE
)
151 if (LE_FAILURE(success
)) {
155 fGlyphStorage
= new LEGlyphStorage();
156 if (fGlyphStorage
== NULL
) {
157 success
= LE_MEMORY_ALLOCATION_ERROR
;
161 le_int32
LayoutEngine::getGlyphCount() const
163 return fGlyphStorage
->getGlyphCount();
166 void LayoutEngine::getCharIndices(le_int32 charIndices
[], le_int32 indexBase
, LEErrorCode
&success
) const
168 fGlyphStorage
->getCharIndices(charIndices
, indexBase
, success
);
171 void LayoutEngine::getCharIndices(le_int32 charIndices
[], LEErrorCode
&success
) const
173 fGlyphStorage
->getCharIndices(charIndices
, success
);
176 // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
177 void LayoutEngine::getGlyphs(le_uint32 glyphs
[], le_uint32 extraBits
, LEErrorCode
&success
) const
179 fGlyphStorage
->getGlyphs(glyphs
, extraBits
, success
);
182 void LayoutEngine::getGlyphs(LEGlyphID glyphs
[], LEErrorCode
&success
) const
184 fGlyphStorage
->getGlyphs(glyphs
, success
);
188 void LayoutEngine::getGlyphPositions(float positions
[], LEErrorCode
&success
) const
190 fGlyphStorage
->getGlyphPositions(positions
, success
);
193 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex
, float &x
, float &y
, LEErrorCode
&success
) const
195 fGlyphStorage
->getGlyphPosition(glyphIndex
, x
, y
, success
);
198 le_int32
LayoutEngine::characterProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
199 LEUnicode
*&outChars
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
201 if (LE_FAILURE(success
)) {
205 if (offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
206 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
210 LEReferenceTo
<GlyphSubstitutionTableHeader
> canonGSUBTable((GlyphSubstitutionTableHeader
*) CanonShaping::glyphSubstitutionTable
);
211 LETag scriptTag
= OpenTypeLayoutEngine::getScriptTag(fScriptCode
);
212 LETag langSysTag
= OpenTypeLayoutEngine::getLangSysTag(fLanguageCode
);
213 le_int32 i
, dir
= 1, out
= 0, outCharCount
= count
;
215 if (canonGSUBTable
->coversScript(canonGSUBTable
,scriptTag
, success
) || LE_SUCCESS(success
)) {
216 CharSubstitutionFilter
*substitutionFilter
= new CharSubstitutionFilter(fFontInstance
);
217 if (substitutionFilter
== NULL
) {
218 success
= LE_MEMORY_ALLOCATION_ERROR
;
222 const LEUnicode
*inChars
= &chars
[offset
];
223 LEUnicode
*reordered
= NULL
;
224 LEGlyphStorage fakeGlyphStorage
;
226 fakeGlyphStorage
.allocateGlyphArray(count
, rightToLeft
, success
);
228 if (LE_FAILURE(success
)) {
229 delete substitutionFilter
;
233 // This is the cheapest way to get mark reordering only for Hebrew.
234 // We could just do the mark reordering for all scripts, but most
235 // of them probably don't need it...
236 if (fScriptCode
== hebrScriptCode
) {
237 reordered
= LE_NEW_ARRAY(LEUnicode
, count
);
239 if (reordered
== NULL
) {
240 delete substitutionFilter
;
241 success
= LE_MEMORY_ALLOCATION_ERROR
;
245 CanonShaping::reorderMarks(&chars
[offset
], count
, rightToLeft
, reordered
, fakeGlyphStorage
);
249 fakeGlyphStorage
.allocateAuxData(success
);
251 if (LE_FAILURE(success
)) {
252 delete substitutionFilter
;
261 for (i
= 0; i
< count
; i
+= 1, out
+= dir
) {
262 fakeGlyphStorage
[out
] = (LEGlyphID
) inChars
[i
];
263 fakeGlyphStorage
.setAuxData(out
, canonFeatures
, success
);
266 if (reordered
!= NULL
) {
267 LE_DELETE_ARRAY(reordered
);
270 outCharCount
= canonGSUBTable
->process(canonGSUBTable
, fakeGlyphStorage
, rightToLeft
, scriptTag
, langSysTag
, (const GlyphDefinitionTableHeader
*)NULL
, substitutionFilter
, canonFeatureMap
, canonFeatureMapCount
, FALSE
, success
);
272 if (LE_FAILURE(success
)) {
273 delete substitutionFilter
;
277 out
= (rightToLeft
? outCharCount
- 1 : 0);
280 * The char indices array in fakeGlyphStorage has the correct mapping
281 * back to the original input characters. Save it in glyphStorage. The
282 * subsequent call to glyphStoratge.allocateGlyphArray will keep this
283 * array rather than allocating and initializing a new one.
285 glyphStorage
.adoptCharIndicesArray(fakeGlyphStorage
);
287 outChars
= LE_NEW_ARRAY(LEUnicode
, outCharCount
);
289 if (outChars
== NULL
) {
290 delete substitutionFilter
;
291 success
= LE_MEMORY_ALLOCATION_ERROR
;
295 for (i
= 0; i
< outCharCount
; i
+= 1, out
+= dir
) {
296 outChars
[out
] = (LEUnicode
) LE_GET_GLYPH(fakeGlyphStorage
[i
]);
299 delete substitutionFilter
;
305 le_int32
LayoutEngine::computeGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
306 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
308 if (LE_FAILURE(success
)) {
312 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
313 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
317 LEUnicode
*outChars
= NULL
;
318 le_int32 outCharCount
= characterProcessing(chars
, offset
, count
, max
, rightToLeft
, outChars
, glyphStorage
, success
);
320 if (outChars
!= NULL
) {
321 mapCharsToGlyphs(outChars
, 0, outCharCount
, rightToLeft
, rightToLeft
, glyphStorage
, success
);
322 LE_DELETE_ARRAY(outChars
); // FIXME: a subclass may have allocated this, in which case this delete might not work...
324 mapCharsToGlyphs(chars
, offset
, count
, rightToLeft
, rightToLeft
, glyphStorage
, success
);
327 return glyphStorage
.getGlyphCount();
332 void LayoutEngine::positionGlyphs(LEGlyphStorage
&glyphStorage
, float x
, float y
, LEErrorCode
&success
)
334 if (LE_FAILURE(success
)) {
338 glyphStorage
.allocatePositions(success
);
340 if (LE_FAILURE(success
)) {
344 le_int32 i
, glyphCount
= glyphStorage
.getGlyphCount();
346 for (i
= 0; i
< glyphCount
; i
+= 1) {
349 glyphStorage
.setPosition(i
, x
, y
, success
);
351 fFontInstance
->getGlyphAdvance(glyphStorage
[i
], advance
);
356 glyphStorage
.setPosition(glyphCount
, x
, y
, success
);
359 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
,
360 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
362 if (LE_FAILURE(success
)) {
366 if (chars
== NULL
|| offset
< 0 || count
< 0) {
367 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
371 LEReferenceTo
<GlyphDefinitionTableHeader
> gdefTable((GlyphDefinitionTableHeader
*) CanonShaping::glyphDefinitionTable
,
372 CanonShaping::glyphDefinitionTableLen
);
373 CanonMarkFilter
filter(gdefTable
, success
);
375 adjustMarkGlyphs(&chars
[offset
], count
, reverse
, glyphStorage
, &filter
, success
);
377 if (fTypoFlags
& LE_Kerning_FEATURE_FLAG
) { /* kerning enabled */
378 LETableReference
kernTable(fFontInstance
, LE_KERN_TABLE_TAG
, success
);
379 KernTable
kt(kernTable
, success
);
380 kt
.process(glyphStorage
, success
);
383 // default is no adjustments
387 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage
&glyphStorage
, LEGlyphFilter
*markFilter
, LEErrorCode
&success
)
390 le_int32 p
, glyphCount
= glyphStorage
.getGlyphCount();
392 if (LE_FAILURE(success
)) {
396 if (markFilter
== NULL
) {
397 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
403 glyphStorage
.getGlyphPosition(0, prev
, ignore
, success
);
405 for (p
= 0; p
< glyphCount
; p
+= 1) {
406 float next
, xAdvance
;
408 glyphStorage
.getGlyphPosition(p
+ 1, next
, ignore
, success
);
410 xAdvance
= next
- prev
;
411 glyphStorage
.adjustPosition(p
, xAdjust
, 0, success
);
413 if (markFilter
->accept(glyphStorage
[p
])) {
420 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, 0, success
);
423 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars
[], le_int32 charCount
, le_bool reverse
, LEGlyphStorage
&glyphStorage
, LEGlyphFilter
*markFilter
, LEErrorCode
&success
)
426 le_int32 c
= 0, direction
= 1, p
;
427 le_int32 glyphCount
= glyphStorage
.getGlyphCount();
429 if (LE_FAILURE(success
)) {
433 if (markFilter
== NULL
) {
434 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
445 glyphStorage
.getGlyphPosition(0, prev
, ignore
, success
);
447 for (p
= 0; p
< charCount
; p
+= 1, c
+= direction
) {
448 float next
, xAdvance
;
450 glyphStorage
.getGlyphPosition(p
+ 1, next
, ignore
, success
);
452 xAdvance
= next
- prev
;
453 glyphStorage
.adjustPosition(p
, xAdjust
, 0, success
);
455 if (markFilter
->accept(chars
[c
])) {
462 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, 0, success
);
465 const void *LayoutEngine::getFontTable(LETag tableTag
, size_t &length
) const
467 return fFontInstance
->getFontTable(tableTag
, length
);
470 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
, le_bool mirror
,
471 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
473 if (LE_FAILURE(success
)) {
477 glyphStorage
.allocateGlyphArray(count
, reverse
, success
);
479 DefaultCharMapper
charMapper(TRUE
, mirror
);
481 fFontInstance
->mapCharsToGlyphs(chars
, offset
, count
, reverse
, &charMapper
, fFilterZeroWidth
, glyphStorage
);
484 // Input: characters, font?
485 // Output: glyphs, positions, char indices
486 // Returns: number of glyphs
487 le_int32
LayoutEngine::layoutChars(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
488 float x
, float y
, LEErrorCode
&success
)
490 if (LE_FAILURE(success
)) {
494 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
495 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
501 if (fGlyphStorage
->getGlyphCount() > 0) {
502 fGlyphStorage
->reset();
505 glyphCount
= computeGlyphs(chars
, offset
, count
, max
, rightToLeft
, *fGlyphStorage
, success
);
506 positionGlyphs(*fGlyphStorage
, x
, y
, success
);
507 adjustGlyphPositions(chars
, offset
, count
, rightToLeft
, *fGlyphStorage
, success
);
512 void LayoutEngine::reset()
514 if(fGlyphStorage
!=NULL
) {
515 fGlyphStorage
->reset();
519 LayoutEngine
*LayoutEngine::layoutEngineFactory(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, LEErrorCode
&success
)
521 //kerning and ligatures - by default
522 return LayoutEngine::layoutEngineFactory(fontInstance
, scriptCode
, languageCode
, LE_DEFAULT_FEATURE_FLAG
, success
);
525 LayoutEngine
*LayoutEngine::layoutEngineFactory(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
, le_int32 typoFlags
, LEErrorCode
&success
)
527 static const le_uint32 gsubTableTag
= LE_GSUB_TABLE_TAG
;
528 static const le_uint32 mortTableTag
= LE_MORT_TABLE_TAG
;
529 static const le_uint32 morxTableTag
= LE_MORX_TABLE_TAG
;
531 if (LE_FAILURE(success
)) {
535 LEReferenceTo
<GlyphSubstitutionTableHeader
> gsubTable(fontInstance
,gsubTableTag
,success
);
536 LayoutEngine
*result
= NULL
;
537 LETag scriptTag
= 0x00000000;
538 LETag languageTag
= 0x00000000;
539 LETag v2ScriptTag
= OpenTypeLayoutEngine::getV2ScriptTag(scriptCode
);
541 // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are
544 if ( v2ScriptTag
== dev2ScriptTag
&& gsubTable
.isValid() && gsubTable
->coversScript(gsubTable
, v2ScriptTag
, success
)) {
545 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, TRUE
, gsubTable
, success
);
547 else if (gsubTable
.isValid() && gsubTable
->coversScript(gsubTable
, scriptTag
= OpenTypeLayoutEngine::getScriptTag(scriptCode
), success
)) {
548 switch (scriptCode
) {
559 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, FALSE
, gsubTable
, success
);
563 result
= new ArabicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
567 // Disable hebrew ligatures since they have only archaic uses, see ticket #8318
568 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
& ~kTypoFlagLiga
, gsubTable
, success
);
572 result
= new HangulOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
576 languageTag
= OpenTypeLayoutEngine::getLangSysTag(languageCode
);
578 switch (languageCode
) {
579 case korLanguageCode
:
580 case janLanguageCode
:
581 case zhtLanguageCode
:
582 case zhsLanguageCode
:
583 if (gsubTable
->coversScriptAndLanguage(gsubTable
, scriptTag
, languageTag
, success
, TRUE
)) {
584 result
= new HanOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
588 // note: falling through to default case.
590 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
597 result
= new TibetanOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
601 result
= new KhmerOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
605 result
= new OpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, gsubTable
, success
);
609 MorphTableHeader2
*morxTable
= (MorphTableHeader2
*)fontInstance
->getFontTable(morxTableTag
);
610 if (morxTable
!= NULL
&& SWAPL(morxTable
->version
)==0x00020000) {
611 result
= new GXLayoutEngine2(fontInstance
, scriptCode
, languageCode
, morxTable
, typoFlags
, success
);
613 LEReferenceTo
<MorphTableHeader
> mortTable(fontInstance
, mortTableTag
, success
);
614 if (LE_SUCCESS(success
) && mortTable
.isValid() && SWAPL(mortTable
->version
)==0x00010000) { // mort
615 result
= new GXLayoutEngine(fontInstance
, scriptCode
, languageCode
, mortTable
, success
);
617 switch (scriptCode
) {
629 result
= new IndicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, success
);
634 //case hebrScriptCode:
635 result
= new UnicodeArabicOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, success
);
638 //case hebrScriptCode:
639 // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
642 result
= new ThaiLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, success
);
646 result
= new HangulOpenTypeLayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, success
);
650 result
= new LayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
, success
);
657 if (result
&& LE_FAILURE(success
)) {
662 if (result
== NULL
) {
663 success
= LE_MEMORY_ALLOCATION_ERROR
;
669 LayoutEngine::~LayoutEngine() {
670 delete fGlyphStorage
;