4 * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
10 #include "LELanguages.h"
12 #include "LayoutEngine.h"
13 #include "OpenTypeLayoutEngine.h"
14 #include "ScriptAndLanguageTags.h"
16 #include "GlyphSubstitutionTables.h"
17 #include "GlyphDefinitionTables.h"
18 #include "GlyphPositioningTables.h"
20 #include "LEGlyphStorage.h"
22 #include "GDEFMarkFilter.h"
26 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine
)
28 static const LETag emptyTag
= 0x00000000;
30 static const LETag ccmpFeatureTag
= LE_CCMP_FEATURE_TAG
;
31 static const LETag ligaFeatureTag
= LE_LIGA_FEATURE_TAG
;
32 static const LETag cligFeatureTag
= LE_CLIG_FEATURE_TAG
;
33 static const LETag kernFeatureTag
= LE_KERN_FEATURE_TAG
;
34 static const LETag markFeatureTag
= LE_MARK_FEATURE_TAG
;
35 static const LETag mkmkFeatureTag
= LE_MKMK_FEATURE_TAG
;
37 static const LETag defaultFeatures
[] = {ccmpFeatureTag
, ligaFeatureTag
, cligFeatureTag
, kernFeatureTag
, markFeatureTag
, mkmkFeatureTag
, emptyTag
};
40 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
,
41 const GlyphSubstitutionTableHeader
*gsubTable
)
42 : LayoutEngine(fontInstance
, scriptCode
, languageCode
), fFeatureList(defaultFeatures
), fFeatureOrder(NULL
),
43 fGSUBTable(gsubTable
), fGDEFTable(NULL
), fGPOSTable(NULL
), fSubstitutionFilter(NULL
)
45 static const le_uint32 gdefTableTag
= LE_GDEF_TABLE_TAG
;
46 static const le_uint32 gposTableTag
= LE_GPOS_TABLE_TAG
;
47 const GlyphPositioningTableHeader
*gposTable
= (const GlyphPositioningTableHeader
*) getFontTable(gposTableTag
);
49 setScriptAndLanguageTags();
51 fGDEFTable
= (const GlyphDefinitionTableHeader
*) getFontTable(gdefTableTag
);
53 if (gposTable
!= NULL
&& gposTable
->coversScriptAndLanguage(fScriptTag
, fLangSysTag
)) {
54 fGPOSTable
= gposTable
;
58 void OpenTypeLayoutEngine::reset()
60 // NOTE: if we're called from
61 // the destructor, LayoutEngine;:reset()
62 // will have been called already by
63 // LayoutEngine::~LayoutEngine()
64 LayoutEngine::reset();
67 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance
*fontInstance
, le_int32 scriptCode
, le_int32 languageCode
)
68 : LayoutEngine(fontInstance
, scriptCode
, languageCode
), fFeatureOrder(NULL
),
69 fGSUBTable(NULL
), fGDEFTable(NULL
), fGPOSTable(NULL
), fSubstitutionFilter(NULL
)
71 setScriptAndLanguageTags();
74 OpenTypeLayoutEngine::~OpenTypeLayoutEngine()
79 LETag
OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode
)
81 if (scriptCode
< 0 || scriptCode
>= scriptCodeCount
) {
85 return scriptTags
[scriptCode
];
88 LETag
OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode
)
90 if (languageCode
< 0 || languageCode
>= languageCodeCount
) {
94 return languageTags
[languageCode
];
97 void OpenTypeLayoutEngine::setScriptAndLanguageTags()
99 fScriptTag
= getScriptTag(fScriptCode
);
100 fLangSysTag
= getLangSysTag(fLanguageCode
);
103 le_int32
OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
104 LEUnicode
*&outChars
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
106 if (LE_FAILURE(success
)) {
110 if (offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
111 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
115 le_int32 outCharCount
= LayoutEngine::characterProcessing(chars
, offset
, count
, max
, rightToLeft
, outChars
, glyphStorage
, success
);
117 if (LE_FAILURE(success
)) {
121 glyphStorage
.allocateGlyphArray(outCharCount
, rightToLeft
, success
);
122 glyphStorage
.allocateAuxData(success
);
124 for (le_int32 i
= 0; i
< outCharCount
; i
+= 1) {
125 glyphStorage
.setAuxData(i
, (void *) fFeatureList
, success
);
131 // Input: characters, tags
132 // Output: glyphs, char indices
133 le_int32
OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
,
134 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
136 if (LE_FAILURE(success
)) {
140 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
141 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
145 mapCharsToGlyphs(chars
, offset
, count
, rightToLeft
, rightToLeft
, glyphStorage
, success
);
147 if (LE_FAILURE(success
)) {
151 if (fGSUBTable
!= NULL
) {
152 count
= fGSUBTable
->process(glyphStorage
, rightToLeft
, fScriptTag
, fLangSysTag
, fGDEFTable
, fSubstitutionFilter
, fFeatureOrder
);
158 le_int32
OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage
&tempGlyphStorage
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
160 if (LE_FAILURE(success
)) {
164 glyphStorage
.adoptGlyphArray(tempGlyphStorage
);
165 glyphStorage
.adoptCharIndicesArray(tempGlyphStorage
);
166 glyphStorage
.adoptAuxDataArray(tempGlyphStorage
);
167 glyphStorage
.adoptGlyphCount(tempGlyphStorage
);
169 return glyphStorage
.getGlyphCount();
172 le_int32
OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_int32 max
, le_bool rightToLeft
, LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
174 LEUnicode
*outChars
= NULL
;
175 LEGlyphStorage fakeGlyphStorage
;
176 le_int32 outCharCount
, outGlyphCount
, fakeGlyphCount
;
178 if (LE_FAILURE(success
)) {
182 if (chars
== NULL
|| offset
< 0 || count
< 0 || max
< 0 || offset
>= max
|| offset
+ count
> max
) {
183 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
187 outCharCount
= characterProcessing(chars
, offset
, count
, max
, rightToLeft
, outChars
, fakeGlyphStorage
, success
);
189 if (outChars
!= NULL
) {
190 fakeGlyphCount
= glyphProcessing(outChars
, 0, outCharCount
, outCharCount
, rightToLeft
, fakeGlyphStorage
, success
);
191 LE_DELETE_ARRAY(outChars
); // FIXME: a subclass may have allocated this, in which case this delete might not work...
192 //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount);
194 fakeGlyphCount
= glyphProcessing(chars
, offset
, count
, max
, rightToLeft
, fakeGlyphStorage
, success
);
195 //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount);
198 outGlyphCount
= glyphPostProcessing(fakeGlyphStorage
, glyphStorage
, success
);
200 return outGlyphCount
;
203 // apply GPOS table, if any
204 void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars
[], le_int32 offset
, le_int32 count
, le_bool reverse
,
205 LEGlyphStorage
&glyphStorage
, LEErrorCode
&success
)
207 if (LE_FAILURE(success
)) {
211 if (chars
== NULL
|| offset
< 0 || count
< 0) {
212 success
= LE_ILLEGAL_ARGUMENT_ERROR
;
216 le_int32 glyphCount
= glyphStorage
.getGlyphCount();
218 if (glyphCount
> 0 && fGPOSTable
!= NULL
) {
219 GlyphPositionAdjustment
*adjustments
= new GlyphPositionAdjustment
[glyphCount
];
222 if (adjustments
== NULL
) {
223 success
= LE_MEMORY_ALLOCATION_ERROR
;
228 // Don't need to do this if we allocate
229 // the adjustments array w/ new...
230 for (i
= 0; i
< glyphCount
; i
+= 1) {
231 adjustments
[i
].setXPlacement(0);
232 adjustments
[i
].setYPlacement(0);
234 adjustments
[i
].setXAdvance(0);
235 adjustments
[i
].setYAdvance(0);
237 adjustments
[i
].setBaseOffset(-1);
241 fGPOSTable
->process(glyphStorage
, adjustments
, reverse
, fScriptTag
, fLangSysTag
, fGDEFTable
, fFontInstance
, fFeatureOrder
);
243 float xAdjust
= 0, yAdjust
= 0;
245 for (i
= 0; i
< glyphCount
; i
+= 1) {
246 float xAdvance
= adjustments
[i
].getXAdvance();
247 float yAdvance
= adjustments
[i
].getYAdvance();
248 float xPlacement
= 0;
249 float yPlacement
= 0;
253 // This is where separate kerning adjustments
254 // should get applied.
259 for (le_int32 base
= i
; base
>= 0; base
= adjustments
[base
].getBaseOffset()) {
260 xPlacement
+= adjustments
[base
].getXPlacement();
261 yPlacement
+= adjustments
[base
].getYPlacement();
264 xPlacement
= fFontInstance
->xUnitsToPoints(xPlacement
);
265 yPlacement
= fFontInstance
->yUnitsToPoints(yPlacement
);
266 glyphStorage
.adjustPosition(i
, xAdjust
+ xPlacement
, -(yAdjust
+ yPlacement
), success
);
268 xAdjust
+= fFontInstance
->xUnitsToPoints(xAdvance
);
269 yAdjust
+= fFontInstance
->yUnitsToPoints(yAdvance
);
272 glyphStorage
.adjustPosition(glyphCount
, xAdjust
, -yAdjust
, success
);
274 delete[] adjustments
;
278 // Don't know why this is here...
279 LE_DELETE_ARRAY(fFeatureTags
);