4 * (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved
10 #include "LELanguages.h"
12 #include "LayoutEngine.h"
13 #include "OpenTypeLayoutEngine.h"
14 #include "ScriptAndLanguageTags.h"
15 #include "CharSubstitutionFilter.h"
17 #include "GlyphSubstitutionTables.h"
18 #include "GlyphDefinitionTables.h"
19 #include "GlyphPositioningTables.h"
21 #include "LEGlyphStorage.h"
22 #include "GlyphPositionAdjustments.h"
24 #include "GDEFMarkFilter.h"
28 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine
)
30 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
31 #define ligaFeatureTag LE_LIGA_FEATURE_TAG
32 #define cligFeatureTag LE_CLIG_FEATURE_TAG
33 #define kernFeatureTag LE_KERN_FEATURE_TAG
34 #define markFeatureTag LE_MARK_FEATURE_TAG
35 #define mkmkFeatureTag LE_MKMK_FEATURE_TAG
37 // 'dlig' not used at the moment
38 #define dligFeatureTag 0x646C6967
41 #define paltFeatureTag 0x70616C74
43 #define ccmpFeatureMask 0x80000000UL
44 #define ligaFeatureMask 0x40000000UL
45 #define cligFeatureMask 0x20000000UL
46 #define kernFeatureMask 0x10000000UL
47 #define paltFeatureMask 0x08000000UL
48 #define markFeatureMask 0x04000000UL
49 #define mkmkFeatureMask 0x02000000UL
51 #define minimalFeatures (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask)
52 #define ligaFeatures (ligaFeatureMask | cligFeatureMask | minimalFeatures)
53 #define kernFeatures (kernFeatureMask | paltFeatureMask | minimalFeatures)
54 #define kernAndLigaFeatures (ligaFeatures | kernFeatures)
56 static const FeatureMap featureMap
[] =
58 {ccmpFeatureTag
, ccmpFeatureMask
},
59 {ligaFeatureTag
, ligaFeatureMask
},
60 {cligFeatureTag
, cligFeatureMask
},
61 {kernFeatureTag
, kernFeatureMask
},
62 {paltFeatureTag
, paltFeatureMask
},
63 {markFeatureTag
, markFeatureMask
},
64 {mkmkFeatureTag
, mkmkFeatureMask
}
67 static const le_int32 featureMapCount
= LE_ARRAY_SIZE(featureMap
);
69 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
,
70 le_int32 typoFlags
, const GlyphSubstitutionTableHeader
*gsubTable
)
71 : LayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
), fFeatureMask(minimalFeatures
),
72 fFeatureMap(featureMap
), fFeatureMapCount(featureMapCount
), fFeatureOrder(FALSE
),
73 fGSUBTable(gsubTable
), fGDEFTable(NULL
), fGPOSTable(NULL
), fSubstitutionFilter(NULL
), fFilterZeroWidth(TRUE
)
75 static const le_uint32 gdefTableTag
= LE_GDEF_TABLE_TAG
;
76 static const le_uint32 gposTableTag
= LE_GPOS_TABLE_TAG
;
77 const GlyphPositioningTableHeader
*gposTable
= (const GlyphPositioningTableHeader
*) getFontTable(gposTableTag
);
79 // todo: switch to more flags and bitfield rather than list of feature tags?
80 switch (typoFlags
& ~0x80000000L
) {
81 case 0: break; // default
82 case 1: fFeatureMask
= kernFeatures
; break;
83 case 2: fFeatureMask
= ligaFeatures
; break;
84 case 3: fFeatureMask
= kernAndLigaFeatures
; break;
88 if (typoFlags
& 0x80000000L
) {
89 fSubstitutionFilter
= new CharSubstitutionFilter(fontInstance
);
92 setScriptAndLanguageTags();
94 fGDEFTable
= (const GlyphDefinitionTableHeader
*) getFontTable(gdefTableTag
);
96 if (gposTable
!= NULL
&& gposTable
->coversScriptAndLanguage(fScriptTag
, fLangSysTag
)) {
97 fGPOSTable
= gposTable
;
101 void OpenTypeLayoutEngine::reset()
103 // NOTE: if we're called from
104 // the destructor, LayoutEngine;:reset()
105 // will have been called already by
106 // LayoutEngine::~LayoutEngine()
107 LayoutEngine::reset();
110 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
,
112 : LayoutEngine(fontInstance
, scriptCode
, languageCode
, typoFlags
), fFeatureOrder(FALSE
),
113 fGSUBTable(NULL
), fGDEFTable(NULL
), fGPOSTable(NULL
), fSubstitutionFilter(NULL
), fFilterZeroWidth(TRUE
)
115 setScriptAndLanguageTags();
118 OpenTypeLayoutEngine::~OpenTypeLayoutEngine()
120 if (fTypoFlags
& 0x80000000L
) {
121 delete fSubstitutionFilter
;
127 LETag
OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode
)
129 if (scriptCode
< 0 || scriptCode
>= scriptCodeCount
) {
133 return scriptTags
[scriptCode
];
136 LETag
OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode
)
138 if (languageCode
< 0 || languageCode
>= languageCodeCount
) {
142 return languageTags
[languageCode
];
145 void OpenTypeLayoutEngine::setScriptAndLanguageTags()
147 fScriptTag
= getScriptTag(fScriptCode
);
148 fLangSysTag
= getLangSysTag(fLanguageCode
);
151 le_int32
OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
152 LEUnicode
*&outChars
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
154 if (LE_FAILURE(success
)) {
158 if (offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
159 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
163 le_int32 outCharCount
= LayoutEngine::characterProcessing(chars
, offset
, count
, max
, rightToLeft
, outChars
, glyphStorage
, success
);
165 if (LE_FAILURE(success
)) {
169 glyphStorage
.allocateGlyphArray(outCharCount
, rightToLeft
, success
);
170 glyphStorage
.allocateAuxData(success
);
172 for (le_int32 i
= 0; i
< outCharCount
; i
+= 1) {
173 glyphStorage
.setAuxData(i
, fFeatureMask
, success
);
179 // Input: characters, tags
180 // Output: glyphs, char indices
181 le_int32
OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
182 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
184 if (LE_FAILURE(success
)) {
188 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
189 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
193 mapCharsToGlyphs(chars
, offset
, count
, rightToLeft
, rightToLeft
, fFilterZeroWidth
, glyphStorage
, success
);
195 if (LE_FAILURE(success
)) {
199 if (fGSUBTable
!= NULL
) {
200 count
= fGSUBTable
->process(glyphStorage
, rightToLeft
, fScriptTag
, fLangSysTag
, fGDEFTable
, fSubstitutionFilter
,
201 fFeatureMap
, fFeatureMapCount
, fFeatureOrder
);
207 le_int32
OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage
&tempGlyphStorage
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
209 if (LE_FAILURE(success
)) {
213 glyphStorage
.adoptGlyphArray(tempGlyphStorage
);
214 glyphStorage
.adoptCharIndicesArray(tempGlyphStorage
);
215 glyphStorage
.adoptAuxDataArray(tempGlyphStorage
);
216 glyphStorage
.adoptGlyphCount(tempGlyphStorage
);
218 return glyphStorage
.getGlyphCount();
221 le_int32
OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
223 LEUnicode
*outChars
= NULL
;
224 LEGlyphStorage fakeGlyphStorage
;
225 le_int32 outCharCount
, outGlyphCount
, fakeGlyphCount
;
227 if (LE_FAILURE(success
)) {
231 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
232 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
236 outCharCount
= characterProcessing(chars
, offset
, count
, max
, rightToLeft
, outChars
, fakeGlyphStorage
, success
);
238 if (LE_FAILURE(success
)) {
242 if (outChars
!= NULL
) {
243 fakeGlyphCount
= glyphProcessing(outChars
, 0, outCharCount
, outCharCount
, rightToLeft
, fakeGlyphStorage
, success
);
244 LE_DELETE_ARRAY(outChars
); // FIXME: a subclass may have allocated this, in which case this delete might not work...
245 //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount);
247 fakeGlyphCount
= glyphProcessing(chars
, offset
, count
, max
, rightToLeft
, fakeGlyphStorage
, success
);
248 //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount);
251 if (LE_FAILURE(success
)) {
255 outGlyphCount
= glyphPostProcessing(fakeGlyphStorage
, glyphStorage
, success
);
257 return outGlyphCount
;
260 // apply GPOS table, if any
261 void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
,
262 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
264 if (LE_FAILURE(success
)) {
268 if (chars
== NULL
|| offset
< 0 || count
< 0) {
269 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
273 le_int32 glyphCount
= glyphStorage
.getGlyphCount();
275 if (glyphCount
> 0 && fGPOSTable
!= NULL
) {
276 GlyphPositionAdjustments
*adjustments
= new GlyphPositionAdjustments(glyphCount
);
279 if (adjustments
== NULL
) {
280 success
= LE_MEMORY_ALLOCATION_ERROR
;
285 // Don't need to do this if we allocate
286 // the adjustments array w/ new...
287 for (i
= 0; i
< glyphCount
; i
+= 1) {
288 adjustments
->setXPlacement(i
, 0);
289 adjustments
->setYPlacement(i
, 0);
291 adjustments
->setXAdvance(i
, 0);
292 adjustments
->setYAdvance(i
, 0);
294 adjustments
->setBaseOffset(i
, -1);
298 fGPOSTable
->process(glyphStorage
, adjustments
, reverse
, fScriptTag
, fLangSysTag
, fGDEFTable
, fFontInstance
,
299 fFeatureMap
, fFeatureMapCount
, fFeatureOrder
);
301 float xAdjust
= 0, yAdjust
= 0;
303 for (i
= 0; i
< glyphCount
; i
+= 1) {
304 float xAdvance
= adjustments
->getXAdvance(i
);
305 float yAdvance
= adjustments
->getYAdvance(i
);
306 float xPlacement
= 0;
307 float yPlacement
= 0;
311 // This is where separate kerning adjustments
312 // should get applied.
317 for (le_int32 base
= i
; base
>= 0; base
= adjustments
->getBaseOffset(base
)) {
318 xPlacement
+= adjustments
->getXPlacement(base
);
319 yPlacement
+= adjustments
->getYPlacement(base
);
322 xPlacement
= fFontInstance
->xUnitsToPoints(xPlacement
);
323 yPlacement
= fFontInstance
->yUnitsToPoints(yPlacement
);
324 glyphStorage
.adjustPosition(i
, xAdjust
+ xPlacement
, -(yAdjust
+ yPlacement
), success
);
326 xAdjust
+= fFontInstance
->xUnitsToPoints(xAdvance
);
327 yAdjust
+= fFontInstance
->yUnitsToPoints(yAdvance
);
330 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, -yAdjust
, success
);
336 // Don't know why this is here...
337 LE_DELETE_ARRAY(fFeatureTags
);