]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | |
2 | /* | |
b75a7d8f | 3 | * |
57a6839d | 4 | * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved |
b75a7d8f A |
5 | * |
6 | */ | |
7 | ||
8 | #include "LETypes.h" | |
9 | #include "LEScripts.h" | |
10 | #include "LEGlyphFilter.h" | |
374ca955 | 11 | #include "LEGlyphStorage.h" |
b75a7d8f A |
12 | #include "LayoutEngine.h" |
13 | #include "OpenTypeLayoutEngine.h" | |
14 | #include "ArabicLayoutEngine.h" | |
15 | #include "ScriptAndLanguageTags.h" | |
374ca955 | 16 | #include "CharSubstitutionFilter.h" |
b75a7d8f A |
17 | |
18 | #include "GlyphSubstitutionTables.h" | |
19 | #include "GlyphDefinitionTables.h" | |
20 | #include "GlyphPositioningTables.h" | |
21 | ||
22 | #include "GDEFMarkFilter.h" | |
23 | ||
24 | #include "ArabicShaping.h" | |
374ca955 | 25 | #include "CanonShaping.h" |
b75a7d8f A |
26 | |
27 | U_NAMESPACE_BEGIN | |
28 | ||
b75a7d8f A |
29 | le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const |
30 | { | |
31 | return fFontInstance->canDisplay((LEUnicode) glyph); | |
32 | } | |
33 | ||
374ca955 | 34 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine) |
b75a7d8f | 35 | |
57a6839d A |
36 | ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, |
37 | le_int32 languageCode, le_int32 typoFlags, | |
38 | const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, | |
39 | LEErrorCode &success) | |
729e4ab9 | 40 | : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) |
b75a7d8f | 41 | { |
73c04bcf A |
42 | fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount); |
43 | fFeatureOrder = TRUE; | |
b75a7d8f A |
44 | } |
45 | ||
57a6839d A |
46 | ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, |
47 | le_int32 languageCode, | |
729e4ab9 A |
48 | le_int32 typoFlags, LEErrorCode &success) |
49 | : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success) | |
b75a7d8f | 50 | { |
73c04bcf A |
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; | |
b75a7d8f A |
59 | } |
60 | ||
61 | ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine() | |
62 | { | |
63 | // nothing to do | |
64 | } | |
65 | ||
66 | // Input: characters | |
67 | // Output: characters, char indices, tags | |
68 | // Returns: output character count | |
57a6839d A |
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) | |
b75a7d8f A |
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 | ||
73c04bcf A |
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); | |
374ca955 | 90 | glyphStorage.allocateAuxData(success); |
b75a7d8f | 91 | |
374ca955 | 92 | if (LE_FAILURE(success)) { |
73c04bcf | 93 | LE_DELETE_ARRAY(outChars); |
b75a7d8f A |
94 | return 0; |
95 | } | |
96 | ||
73c04bcf A |
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. | |
374ca955 | 102 | ArabicShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage); |
b75a7d8f A |
103 | |
104 | return count; | |
105 | } | |
106 | ||
107 | void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, | |
374ca955 | 108 | LEGlyphStorage &glyphStorage, LEErrorCode &success) |
b75a7d8f A |
109 | { |
110 | if (LE_FAILURE(success)) { | |
111 | return; | |
112 | } | |
113 | ||
374ca955 | 114 | if (chars == NULL || offset < 0 || count < 0) { |
b75a7d8f A |
115 | success = LE_ILLEGAL_ARGUMENT_ERROR; |
116 | return; | |
117 | } | |
118 | ||
57a6839d | 119 | if (!fGPOSTable.isEmpty()) { |
374ca955 | 120 | OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success); |
57a6839d A |
121 | } else if (!fGDEFTable.isEmpty()) { |
122 | GDEFMarkFilter filter(fGDEFTable, success); | |
374ca955 | 123 | adjustMarkGlyphs(glyphStorage, &filter, success); |
b75a7d8f | 124 | } else { |
57a6839d A |
125 | LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen); |
126 | GDEFMarkFilter filter(gdefTable, success); | |
b75a7d8f | 127 | |
374ca955 | 128 | adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); |
b75a7d8f A |
129 | } |
130 | } | |
131 | ||
729e4ab9 | 132 | UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) |
57a6839d | 133 | : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success) |
b75a7d8f | 134 | { |
374ca955 A |
135 | fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; |
136 | fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; | |
57a6839d | 137 | /* OpenTypeLayoutEngine will allocate a substitution filter */ |
b75a7d8f A |
138 | } |
139 | ||
140 | UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine() | |
141 | { | |
57a6839d | 142 | /* OpenTypeLayoutEngine will cleanup the substitution filter */ |
b75a7d8f A |
143 | } |
144 | ||
145 | // "glyphs", "indices" -> glyphs, indices | |
374ca955 | 146 | le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success) |
b75a7d8f A |
147 | { |
148 | if (LE_FAILURE(success)) { | |
149 | return 0; | |
150 | } | |
151 | ||
b75a7d8f A |
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. | |
374ca955 | 155 | le_int32 tempGlyphCount = tempGlyphStorage.getGlyphCount(); |
b75a7d8f A |
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) { | |
374ca955 | 164 | tempChars[i] = (LEUnicode) LE_GET_GLYPH(tempGlyphStorage[i]); |
b75a7d8f A |
165 | } |
166 | ||
374ca955 | 167 | glyphStorage.adoptCharIndicesArray(tempGlyphStorage); |
b75a7d8f | 168 | |
46f4442e | 169 | ArabicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, tempGlyphCount, FALSE, TRUE, glyphStorage, success); |
b75a7d8f A |
170 | |
171 | LE_DELETE_ARRAY(tempChars); | |
172 | ||
173 | return tempGlyphCount; | |
174 | } | |
175 | ||
46f4442e | 176 | void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool /*mirror*/, LEGlyphStorage &glyphStorage, LEErrorCode &success) |
b75a7d8f A |
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 | ||
374ca955 | 187 | le_int32 i, dir = 1, out = 0; |
b75a7d8f A |
188 | |
189 | if (reverse) { | |
190 | out = count - 1; | |
191 | dir = -1; | |
192 | } | |
193 | ||
374ca955 | 194 | glyphStorage.allocateGlyphArray(count, reverse, success); |
b75a7d8f A |
195 | |
196 | for (i = 0; i < count; i += 1, out += dir) { | |
374ca955 | 197 | glyphStorage[out] = (LEGlyphID) chars[offset + i]; |
b75a7d8f A |
198 | } |
199 | } | |
200 | ||
201 | void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, | |
374ca955 | 202 | LEGlyphStorage &glyphStorage, LEErrorCode &success) |
b75a7d8f A |
203 | { |
204 | if (LE_FAILURE(success)) { | |
205 | return; | |
206 | } | |
207 | ||
374ca955 | 208 | if (chars == NULL || offset < 0 || count < 0) { |
b75a7d8f A |
209 | success = LE_ILLEGAL_ARGUMENT_ERROR; |
210 | return; | |
211 | } | |
212 | ||
57a6839d | 213 | GDEFMarkFilter filter(fGDEFTable, success); |
b75a7d8f | 214 | |
374ca955 | 215 | adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); |
b75a7d8f A |
216 | } |
217 | ||
218 | U_NAMESPACE_END | |
219 |