4 * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
10 #include "LELanguages.h"
12 #include "LayoutEngine.h"
13 #include "CanonShaping.h"
14 #include "OpenTypeLayoutEngine.h"
15 #include "ScriptAndLanguageTags.h"
16 #include "CharSubstitutionFilter.h"
18 #include "GlyphSubstitutionTables.h"
19 #include "GlyphDefinitionTables.h"
20 #include "GlyphPositioningTables.h"
22 #include "LEGlyphStorage.h"
23 #include "GlyphPositionAdjustments.h"
25 #include "GDEFMarkFilter.h"
29 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine
)
31 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
32 #define ligaFeatureTag LE_LIGA_FEATURE_TAG
33 #define cligFeatureTag LE_CLIG_FEATURE_TAG
34 #define kernFeatureTag LE_KERN_FEATURE_TAG
35 #define markFeatureTag LE_MARK_FEATURE_TAG
36 #define mkmkFeatureTag LE_MKMK_FEATURE_TAG
37 #define loclFeatureTag LE_LOCL_FEATURE_TAG
39 // 'dlig' not used at the moment
40 #define dligFeatureTag 0x646C6967
43 #define paltFeatureTag 0x70616C74
45 #define ccmpFeatureMask 0x80000000UL
46 #define ligaFeatureMask 0x40000000UL
47 #define cligFeatureMask 0x20000000UL
48 #define kernFeatureMask 0x10000000UL
49 #define paltFeatureMask 0x08000000UL
50 #define markFeatureMask 0x04000000UL
51 #define mkmkFeatureMask 0x02000000UL
52 #define loclFeatureMask 0x01000000UL
54 #define minimalFeatures (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask | loclFeatureMask)
55 #define ligaFeatures (ligaFeatureMask | cligFeatureMask | minimalFeatures)
56 #define kernFeatures (kernFeatureMask | paltFeatureMask | minimalFeatures)
57 #define kernAndLigaFeatures (ligaFeatures | kernFeatures)
59 static const FeatureMap featureMap
[] =
61 {ccmpFeatureTag
, ccmpFeatureMask
},
62 {ligaFeatureTag
, ligaFeatureMask
},
63 {cligFeatureTag
, cligFeatureMask
},
64 {kernFeatureTag
, kernFeatureMask
},
65 {paltFeatureTag
, paltFeatureMask
},
66 {markFeatureTag
, markFeatureMask
},
67 {mkmkFeatureTag
, mkmkFeatureMask
},
68 {loclFeatureTag
, loclFeatureMask
}
71 static const le_int32 featureMapCount
= LE_ARRAY_SIZE(featureMap
);
73 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
,
74 le_int32 typoFlags
, const GlyphSubstitutionTableHeader
*gsubTable
)
75 : LayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
), fFeatureMask(minimalFeatures
),
76 fFeatureMap(featureMap
), fFeatureMapCount(featureMapCount
), fFeatureOrder(FALSE
),
77 fGSUBTable(gsubTable
), fGDEFTable(NULL
), fGPOSTable(NULL
), fSubstitutionFilter(NULL
)
79 static const le_uint32 gdefTableTag
= LE_GDEF_TABLE_TAG
;
80 static const le_uint32 gposTableTag
= LE_GPOS_TABLE_TAG
;
81 const GlyphPositioningTableHeader
*gposTable
= (const GlyphPositioningTableHeader
*) getFontTable(gposTableTag
);
83 // todo: switch to more flags and bitfield rather than list of feature tags?
84 switch (typoFlags
& ~0x80000000L
) {
85 case 0: break; // default
86 case 1: fFeatureMask
= kernFeatures
; break;
87 case 2: fFeatureMask
= ligaFeatures
; break;
88 case 3: fFeatureMask
= kernAndLigaFeatures
; break;
92 if (typoFlags
& 0x80000000L
) {
93 fSubstitutionFilter
= new CharSubstitutionFilter(fontInstance
);
96 setScriptAndLanguageTags();
98 fGDEFTable
= (const GlyphDefinitionTableHeader
*) getFontTable(gdefTableTag
);
100 if (gposTable
!= NULL
&& gposTable
->coversScriptAndLanguage(fScriptTag
, fLangSysTag
)) {
101 fGPOSTable
= gposTable
;
105 void OpenTypeLayoutEngine::reset()
107 // NOTE: if we're called from
108 // the destructor, LayoutEngine;:reset()
109 // will have been called already by
110 // LayoutEngine::~LayoutEngine()
111 LayoutEngine::reset();
114 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
,
116 : LayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
), fFeatureOrder(FALSE
),
117 fGSUBTable(NULL
), fGDEFTable(NULL
), fGPOSTable(NULL
), fSubstitutionFilter(NULL
)
119 setScriptAndLanguageTags();
122 OpenTypeLayoutEngine::~OpenTypeLayoutEngine()
124 if (fTypoFlags
& 0x80000000L
) {
125 delete fSubstitutionFilter
;
131 LETag
OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode
)
133 if (scriptCode
< 0 || scriptCode
>= scriptCodeCount
) {
137 return scriptTags
[scriptCode
];
140 LETag
OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode
)
142 if (languageCode
< 0 || languageCode
>= languageCodeCount
) {
146 return languageTags
[languageCode
];
149 void OpenTypeLayoutEngine::setScriptAndLanguageTags()
151 fScriptTag
= getScriptTag(fScriptCode
);
152 fLangSysTag
= getLangSysTag(fLanguageCode
);
155 le_int32
OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
156 LEUnicode
*&outChars
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
158 if (LE_FAILURE(success
)) {
162 if (offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
163 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
167 // This is the cheapest way to get mark reordering only for Hebrew.
168 // We could just do the mark reordering for all scripts, but most
169 // of them probably don't need it... Another option would be to
170 // add a HebrewOpenTypeLayoutEngine subclass, but the only thing it
171 // would need to do is mark reordering, so that seems like overkill.
172 if (fScriptCode
== hebrScriptCode
) {
173 outChars
= LE_NEW_ARRAY(LEUnicode
, count
);
175 if (outChars
== NULL
) {
176 success
= LE_MEMORY_ALLOCATION_ERROR
;
180 CanonShaping::reorderMarks(&chars
[offset
], count
, rightToLeft
, outChars
, glyphStorage
);
183 glyphStorage
.allocateGlyphArray(count
, rightToLeft
, success
);
184 glyphStorage
.allocateAuxData(success
);
186 for (le_int32 i
= 0; i
< count
; i
+= 1) {
187 glyphStorage
.setAuxData(i
, fFeatureMask
, success
);
193 // Input: characters, tags
194 // Output: glyphs, char indices
195 le_int32
OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
196 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
198 if (LE_FAILURE(success
)) {
202 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
203 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
207 mapCharsToGlyphs(chars
, offset
, count
, rightToLeft
, rightToLeft
, glyphStorage
, success
);
209 if (LE_FAILURE(success
)) {
213 if (fGSUBTable
!= NULL
) {
214 count
= fGSUBTable
->process(glyphStorage
, rightToLeft
, fScriptTag
, fLangSysTag
, fGDEFTable
, fSubstitutionFilter
,
215 fFeatureMap
, fFeatureMapCount
, fFeatureOrder
);
221 le_int32
OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage
&tempGlyphStorage
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
223 if (LE_FAILURE(success
)) {
227 glyphStorage
.adoptGlyphArray(tempGlyphStorage
);
228 glyphStorage
.adoptCharIndicesArray(tempGlyphStorage
);
229 glyphStorage
.adoptAuxDataArray(tempGlyphStorage
);
230 glyphStorage
.adoptGlyphCount(tempGlyphStorage
);
232 return glyphStorage
.getGlyphCount();
235 le_int32
OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
237 LEUnicode
*outChars
= NULL
;
238 LEGlyphStorage fakeGlyphStorage
;
239 le_int32 outCharCount
, outGlyphCount
, fakeGlyphCount
;
241 if (LE_FAILURE(success
)) {
245 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
246 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
250 outCharCount
= characterProcessing(chars
, offset
, count
, max
, rightToLeft
, outChars
, fakeGlyphStorage
, success
);
252 if (LE_FAILURE(success
)) {
256 if (outChars
!= NULL
) {
257 fakeGlyphCount
= glyphProcessing(outChars
, 0, outCharCount
, outCharCount
, rightToLeft
, fakeGlyphStorage
, success
);
258 LE_DELETE_ARRAY(outChars
); // FIXME: a subclass may have allocated this, in which case this delete might not work...
259 //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount);
261 fakeGlyphCount
= glyphProcessing(chars
, offset
, count
, max
, rightToLeft
, fakeGlyphStorage
, success
);
262 //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount);
265 if (LE_FAILURE(success
)) {
269 outGlyphCount
= glyphPostProcessing(fakeGlyphStorage
, glyphStorage
, success
);
271 return outGlyphCount
;
274 // apply GPOS table, if any
275 void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
,
276 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
278 if (LE_FAILURE(success
)) {
282 if (chars
== NULL
|| offset
< 0 || count
< 0) {
283 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
287 le_int32 glyphCount
= glyphStorage
.getGlyphCount();
289 if (glyphCount
> 0 && fGPOSTable
!= NULL
) {
290 GlyphPositionAdjustments
*adjustments
= new GlyphPositionAdjustments(glyphCount
);
293 if (adjustments
== NULL
) {
294 success
= LE_MEMORY_ALLOCATION_ERROR
;
299 // Don't need to do this if we allocate
300 // the adjustments array w/ new...
301 for (i
= 0; i
< glyphCount
; i
+= 1) {
302 adjustments
->setXPlacement(i
, 0);
303 adjustments
->setYPlacement(i
, 0);
305 adjustments
->setXAdvance(i
, 0);
306 adjustments
->setYAdvance(i
, 0);
308 adjustments
->setBaseOffset(i
, -1);
312 fGPOSTable
->process(glyphStorage
, adjustments
, reverse
, fScriptTag
, fLangSysTag
, fGDEFTable
, fFontInstance
,
313 fFeatureMap
, fFeatureMapCount
, fFeatureOrder
);
315 float xAdjust
= 0, yAdjust
= 0;
317 for (i
= 0; i
< glyphCount
; i
+= 1) {
318 float xAdvance
= adjustments
->getXAdvance(i
);
319 float yAdvance
= adjustments
->getYAdvance(i
);
320 float xPlacement
= 0;
321 float yPlacement
= 0;
325 // This is where separate kerning adjustments
326 // should get applied.
331 for (le_int32 base
= i
; base
>= 0; base
= adjustments
->getBaseOffset(base
)) {
332 xPlacement
+= adjustments
->getXPlacement(base
);
333 yPlacement
+= adjustments
->getYPlacement(base
);
336 xPlacement
= fFontInstance
->xUnitsToPoints(xPlacement
);
337 yPlacement
= fFontInstance
->yUnitsToPoints(yPlacement
);
338 glyphStorage
.adjustPosition(i
, xAdjust
+ xPlacement
, -(yAdjust
+ yPlacement
), success
);
340 xAdjust
+= fFontInstance
->xUnitsToPoints(xAdvance
);
341 yAdjust
+= fFontInstance
->yUnitsToPoints(yAdvance
);
344 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, -yAdjust
, success
);
349 LEGlyphID zwnj
= fFontInstance
->mapCharToGlyph(0x200C);
351 if (zwnj
!= 0x0000) {
352 for (le_int32 g
= 0; g
< glyphCount
; g
+= 1) {
353 LEGlyphID glyph
= glyphStorage
[g
];
356 glyphStorage
[g
] = LE_SET_GLYPH(glyph
, 0xFFFF);
362 // Don't know why this is here...
363 LE_DELETE_ARRAY(fFeatureTags
);