1
2 /*
3 *
4 * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved
5 *
6 */
7
8 #include "LETypes.h"
9 #include "LEScripts.h"
10 #include "LEGlyphFilter.h"
11 #include "LEGlyphStorage.h"
12 #include "LayoutEngine.h"
13 #include "OpenTypeLayoutEngine.h"
14 #include "ArabicLayoutEngine.h"
15 #include "ScriptAndLanguageTags.h"
16 #include "CharSubstitutionFilter.h"
17
18 #include "GlyphSubstitutionTables.h"
19 #include "GlyphDefinitionTables.h"
20 #include "GlyphPositioningTables.h"
21
22 #include "GDEFMarkFilter.h"
23
24 #include "ArabicShaping.h"
25 #include "CanonShaping.h"
26
27 U_NAMESPACE_BEGIN
28
accept(LEGlyphID glyph) const29 le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const
30 {
31 return fFontInstance->canDisplay((LEUnicode) glyph);
32 }
33
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine)34 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine)
35
36 ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode,
37 le_int32 languageCode, le_int32 typoFlags,
38 const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable,
39 LEErrorCode &success)
40 : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success)
41 {
42 fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount);
43 fFeatureOrder = TRUE;
44 }
45
ArabicOpenTypeLayoutEngine(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags,LEErrorCode & success)46 ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode,
47 le_int32 languageCode,
48 le_int32 typoFlags, LEErrorCode &success)
49 : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
50 {
51 fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount);
52
53 // NOTE: We don't need to set fFeatureOrder to TRUE here
54 // because this constructor is only called by the constructor
55 // for UnicodeArabicOpenTypeLayoutEngine, which uses a pre-built
56 // GSUB table that has the features in the correct order.
57
58 //fFeatureOrder = TRUE;
59 }
60
~ArabicOpenTypeLayoutEngine()61 ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine()
62 {
63 // nothing to do
64 }
65
66 // Input: characters
67 // Output: characters, char indices, tags
68 // Returns: output character count
characterProcessing(const LEUnicode chars[],le_int32 offset,le_int32 count,le_int32 max,le_bool rightToLeft,LEUnicode * & outChars,LEGlyphStorage & glyphStorage,LEErrorCode & success)69 le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count,
70 le_int32 max, le_bool rightToLeft, LEUnicode *&outChars,
71 LEGlyphStorage &glyphStorage, LEErrorCode &success)
72 {
73 if (LE_FAILURE(success)) {
74 return 0;
75 }
76
77 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
78 success = LE_ILLEGAL_ARGUMENT_ERROR;
79 return 0;
80 }
81
82 outChars = LE_NEW_ARRAY(LEUnicode, count);
83
84 if (outChars == NULL) {
85 success = LE_MEMORY_ALLOCATION_ERROR;
86 return 0;
87 }
88
89 glyphStorage.allocateGlyphArray(count, rightToLeft, success);
90 glyphStorage.allocateAuxData(success);
91
92 if (LE_FAILURE(success)) {
93 LE_DELETE_ARRAY(outChars);
94 return 0;
95 }
96
97 CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage);
98
99 // Note: This processes the *original* character array so we can get context
100 // for the first and last characters. This is OK because only the marks
101 // will have been reordered, and they don't contribute to shaping.
102 ArabicShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage);
103
104 return count;
105 }
106
adjustGlyphPositions(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,LEGlyphStorage & glyphStorage,LEErrorCode & success)107 void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
108 LEGlyphStorage &glyphStorage, LEErrorCode &success)
109 {
110 if (LE_FAILURE(success)) {
111 return;
112 }
113
114 if (chars == NULL || offset < 0 || count < 0) {
115 success = LE_ILLEGAL_ARGUMENT_ERROR;
116 return;
117 }
118
119 if (!fGPOSTable.isEmpty()) {
120 OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success);
121 } else if (!fGDEFTable.isEmpty()) {
122 GDEFMarkFilter filter(fGDEFTable, success);
123 adjustMarkGlyphs(glyphStorage, &filter, success);
124 } else {
125 LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen);
126 GDEFMarkFilter filter(gdefTable, success);
127
128 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
129 }
130 }
131
UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance * fontInstance,le_int32 scriptCode,le_int32 languageCode,le_int32 typoFlags,LEErrorCode & success)132 UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
133 : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success)
134 {
135 fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
136 fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
137 /* OpenTypeLayoutEngine will allocate a substitution filter */
138 }
139
~UnicodeArabicOpenTypeLayoutEngine()140 UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine()
141 {
142 /* OpenTypeLayoutEngine will cleanup the substitution filter */
143 }
144
145 // "glyphs", "indices" -> glyphs, indices
glyphPostProcessing(LEGlyphStorage & tempGlyphStorage,LEGlyphStorage & glyphStorage,LEErrorCode & success)146 le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success)
147 {
148 if (LE_FAILURE(success)) {
149 return 0;
150 }
151
152 // FIXME: we could avoid the memory allocation and copy if we
153 // made a clone of mapCharsToGlyphs which took the fake glyphs
154 // directly.
155 le_int32 tempGlyphCount = tempGlyphStorage.getGlyphCount();
156 LEUnicode *tempChars = LE_NEW_ARRAY(LEUnicode, tempGlyphCount);
157
158 if (tempChars == NULL) {
159 success = LE_MEMORY_ALLOCATION_ERROR;
160 return 0;
161 }
162
163 for (le_int32 i = 0; i < tempGlyphCount; i += 1) {
164 tempChars[i] = (LEUnicode) LE_GET_GLYPH(tempGlyphStorage[i]);
165 }
166
167 glyphStorage.adoptCharIndicesArray(tempGlyphStorage);
168
169 ArabicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, tempGlyphCount, FALSE, TRUE, glyphStorage, success);
170
171 LE_DELETE_ARRAY(tempChars);
172
173 return tempGlyphCount;
174 }
175
mapCharsToGlyphs(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,le_bool,LEGlyphStorage & glyphStorage,LEErrorCode & success)176 void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool /*mirror*/, LEGlyphStorage &glyphStorage, LEErrorCode &success)
177 {
178 if (LE_FAILURE(success)) {
179 return;
180 }
181
182 if (chars == NULL || offset < 0 || count < 0) {
183 success = LE_ILLEGAL_ARGUMENT_ERROR;
184 return;
185 }
186
187 le_int32 i, dir = 1, out = 0;
188
189 if (reverse) {
190 out = count - 1;
191 dir = -1;
192 }
193
194 glyphStorage.allocateGlyphArray(count, reverse, success);
195
196 for (i = 0; i < count; i += 1, out += dir) {
197 glyphStorage[out] = (LEGlyphID) chars[offset + i];
198 }
199 }
200
adjustGlyphPositions(const LEUnicode chars[],le_int32 offset,le_int32 count,le_bool reverse,LEGlyphStorage & glyphStorage,LEErrorCode & success)201 void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
202 LEGlyphStorage &glyphStorage, LEErrorCode &success)
203 {
204 if (LE_FAILURE(success)) {
205 return;
206 }
207
208 if (chars == NULL || offset < 0 || count < 0) {
209 success = LE_ILLEGAL_ARGUMENT_ERROR;
210 return;
211 }
212
213 GDEFMarkFilter filter(fGDEFTable, success);
214
215 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
216 }
217
218 U_NAMESPACE_END
219
220