]>
Commit | Line | Data |
---|---|---|
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 | ||
29 | le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const | |
30 | { | |
31 | return fFontInstance->canDisplay((LEUnicode) glyph); | |
32 | } | |
33 | ||
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 | ||
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 | ||
61 | ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine() | |
62 | { | |
63 | // nothing to do | |
64 | } | |
65 | ||
66 | // Input: characters | |
67 | // Output: characters, char indices, tags | |
68 | // Returns: output character count | |
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 | ||
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 | ||
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 | ||
140 | UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine() | |
141 | { | |
142 | /* OpenTypeLayoutEngine will cleanup the substitution filter */ | |
143 | } | |
144 | ||
145 | // "glyphs", "indices" -> glyphs, indices | |
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 | ||
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 | ||
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 |