[USP10] Sync with Wine Staging 2.9. CORE-13362
[reactos.git] / reactos / dll / win32 / usp10 / shape.c
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
3 *
4 * Copyright 2010 CodeWeavers, Aric Stewart
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 */
21
22 #include "usp10_internal.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
25
26 #define FIRST_ARABIC_CHAR 0x0600
27 #define LAST_ARABIC_CHAR 0x06ff
28
29 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
30 WCHAR*, INT, WORD*, INT*, INT, WORD*);
31
32 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
33 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
34 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
35 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
36 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
37 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
38 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
39 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
40 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
41 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
42 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
43 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52
53 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
54
55 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
56 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
57 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
58 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
59 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
60 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
61 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
62 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
63 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
64 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
65 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
66 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
67 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
68 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
73 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74
75 extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
76 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
77 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
78
79 enum joining_types {
80 jtU,
81 jtT,
82 jtR,
83 jtL,
84 jtD,
85 jtC
86 };
87
88 enum joined_forms {
89 Xn=0,
90 Xr,
91 Xl,
92 Xm,
93 /* Syriac Alaph */
94 Afj,
95 Afn,
96 Afx
97 };
98
99 typedef struct tagVowelComponents
100 {
101 WCHAR base;
102 WCHAR parts[3];
103 } VowelComponents;
104
105 typedef struct tagConsonantComponents
106 {
107 WCHAR parts[3];
108 WCHAR output;
109 } ConsonantComponents;
110
111 typedef void (*second_reorder_function)(const WCHAR *chars, const IndicSyllable *syllable,
112 WORD *glyphs, const IndicSyllable *glyph_index, lexical_function lex);
113
114 typedef int (*combining_lexical_function)(WCHAR c);
115
116 /* the orders of joined_forms and contextual_features need to line up */
117 static const char *const contextual_features[] =
118 {
119 "isol",
120 "fina",
121 "init",
122 "medi",
123 /* Syriac Alaph */
124 "med2",
125 "fin2",
126 "fin3"
127 };
128
129 static OPENTYPE_FEATURE_RECORD standard_features[] =
130 {
131 { MS_MAKE_TAG('c','c','m','p'), 1},
132 { MS_MAKE_TAG('l','o','c','l'), 1},
133 };
134
135 static OPENTYPE_FEATURE_RECORD latin_features[] =
136 {
137 { MS_MAKE_TAG('l','o','c','l'), 1},
138 { MS_MAKE_TAG('c','c','m','p'), 1},
139 { MS_MAKE_TAG('l','i','g','a'), 1},
140 { MS_MAKE_TAG('c','l','i','g'), 1},
141 };
142
143 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
144 {
145 { MS_MAKE_TAG('k','e','r','n'), 1},
146 { MS_MAKE_TAG('m','a','r','k'), 1},
147 { MS_MAKE_TAG('m','k','m','k'), 1},
148 };
149
150 static OPENTYPE_FEATURE_RECORD arabic_features[] =
151 {
152 { MS_MAKE_TAG('r','l','i','g'), 1},
153 { MS_MAKE_TAG('c','a','l','t'), 1},
154 { MS_MAKE_TAG('l','i','g','a'), 1},
155 { MS_MAKE_TAG('d','l','i','g'), 1},
156 { MS_MAKE_TAG('c','s','w','h'), 1},
157 { MS_MAKE_TAG('m','s','e','t'), 1},
158 };
159
160 static const char *const required_arabic_features[] =
161 {
162 "fina",
163 "init",
164 "medi",
165 "rlig",
166 NULL
167 };
168
169 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
170 {
171 { MS_MAKE_TAG('c','u','r','s'), 1},
172 { MS_MAKE_TAG('k','e','r','n'), 1},
173 { MS_MAKE_TAG('m','a','r','k'), 1},
174 { MS_MAKE_TAG('m','k','m','k'), 1},
175 };
176
177 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
178 {
179 { MS_MAKE_TAG('c','c','m','p'), 1},
180 { MS_MAKE_TAG('d','l','i','g'), 0},
181 };
182
183 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
184 {
185 { MS_MAKE_TAG('k','e','r','n'), 1},
186 { MS_MAKE_TAG('m','a','r','k'), 1},
187 };
188
189 static OPENTYPE_FEATURE_RECORD syriac_features[] =
190 {
191 { MS_MAKE_TAG('r','l','i','g'), 1},
192 { MS_MAKE_TAG('c','a','l','t'), 1},
193 { MS_MAKE_TAG('l','i','g','a'), 1},
194 { MS_MAKE_TAG('d','l','i','g'), 1},
195 };
196
197 static const char *const required_syriac_features[] =
198 {
199 "fina",
200 "fin2",
201 "fin3",
202 "init",
203 "medi",
204 "med2",
205 "rlig",
206 NULL
207 };
208
209 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
210 {
211 { MS_MAKE_TAG('k','e','r','n'), 1},
212 { MS_MAKE_TAG('m','a','r','k'), 1},
213 { MS_MAKE_TAG('m','k','m','k'), 1},
214 };
215
216 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
217 {
218 /* Presentation forms */
219 { MS_MAKE_TAG('b','l','w','s'), 1},
220 { MS_MAKE_TAG('a','b','v','s'), 1},
221 { MS_MAKE_TAG('p','s','t','s'), 1},
222 };
223
224 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
225 {
226 { MS_MAKE_TAG('a','b','v','s'), 1},
227 { MS_MAKE_TAG('b','l','w','s'), 1},
228 };
229
230 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
231 {
232 { MS_MAKE_TAG('a','b','v','m'), 1},
233 { MS_MAKE_TAG('b','l','w','m'), 1},
234 };
235
236 static OPENTYPE_FEATURE_RECORD phags_features[] =
237 {
238 { MS_MAKE_TAG('a','b','v','s'), 1},
239 { MS_MAKE_TAG('b','l','w','s'), 1},
240 { MS_MAKE_TAG('c','a','l','t'), 1},
241 };
242
243 static OPENTYPE_FEATURE_RECORD thai_features[] =
244 {
245 { MS_MAKE_TAG('c','c','m','p'), 1},
246 };
247
248 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
249 {
250 { MS_MAKE_TAG('k','e','r','n'), 1},
251 { MS_MAKE_TAG('m','a','r','k'), 1},
252 { MS_MAKE_TAG('m','k','m','k'), 1},
253 };
254
255 static const char *const required_lao_features[] =
256 {
257 "ccmp",
258 NULL
259 };
260
261 static const char *const required_devanagari_features[] =
262 {
263 "nukt",
264 "akhn",
265 "rphf",
266 "blwf",
267 "half",
268 "vatu",
269 "pres",
270 "abvs",
271 "blws",
272 "psts",
273 "haln",
274 NULL
275 };
276
277 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
278 {
279 { MS_MAKE_TAG('p','r','e','s'), 1},
280 { MS_MAKE_TAG('a','b','v','s'), 1},
281 { MS_MAKE_TAG('b','l','w','s'), 1},
282 { MS_MAKE_TAG('p','s','t','s'), 1},
283 { MS_MAKE_TAG('h','a','l','n'), 1},
284 { MS_MAKE_TAG('c','a','l','t'), 1},
285 };
286
287 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
288 {
289 { MS_MAKE_TAG('k','e','r','n'), 1},
290 { MS_MAKE_TAG('d','i','s','t'), 1},
291 { MS_MAKE_TAG('a','b','v','m'), 1},
292 { MS_MAKE_TAG('b','l','w','m'), 1},
293 };
294
295 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
296 {
297 { MS_MAKE_TAG('l','i','g','a'), 1},
298 { MS_MAKE_TAG('c','l','i','g'), 1},
299 };
300
301 static const char *const required_bengali_features[] =
302 {
303 "nukt",
304 "akhn",
305 "rphf",
306 "blwf",
307 "half",
308 "vatu",
309 "pstf",
310 "init",
311 "abvs",
312 "blws",
313 "psts",
314 "haln",
315 NULL
316 };
317
318 static const char *const required_gurmukhi_features[] =
319 {
320 "nukt",
321 "akhn",
322 "rphf",
323 "blwf",
324 "half",
325 "pstf",
326 "vatu",
327 "cjct",
328 "pres",
329 "abvs",
330 "blws",
331 "psts",
332 "haln",
333 "calt",
334 NULL
335 };
336
337 static const char *const required_oriya_features[] =
338 {
339 "nukt",
340 "akhn",
341 "rphf",
342 "blwf",
343 "pstf",
344 "cjct",
345 "pres",
346 "abvs",
347 "blws",
348 "psts",
349 "haln",
350 "calt",
351 NULL
352 };
353
354 static const char *const required_tamil_features[] =
355 {
356 "nukt",
357 "akhn",
358 "rphf",
359 "pref",
360 "half",
361 "pres",
362 "abvs",
363 "blws",
364 "psts",
365 "haln",
366 "calt",
367 NULL
368 };
369
370 static const char *const required_telugu_features[] =
371 {
372 "nukt",
373 "akhn",
374 "rphf",
375 "pref",
376 "half",
377 "pstf",
378 "cjct",
379 "pres",
380 "abvs",
381 "blws",
382 "psts",
383 "haln",
384 "calt",
385 NULL
386 };
387
388 static OPENTYPE_FEATURE_RECORD khmer_features[] =
389 {
390 { MS_MAKE_TAG('p','r','e','s'), 1},
391 { MS_MAKE_TAG('b','l','w','s'), 1},
392 { MS_MAKE_TAG('a','b','v','s'), 1},
393 { MS_MAKE_TAG('p','s','t','s'), 1},
394 { MS_MAKE_TAG('c','l','i','g'), 1},
395 };
396
397 static const char *const required_khmer_features[] =
398 {
399 "pref",
400 "blwf",
401 "abvf",
402 "pstf",
403 "pres",
404 "blws",
405 "abvs",
406 "psts",
407 "clig",
408 NULL
409 };
410
411 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
412 {
413 { MS_MAKE_TAG('d','i','s','t'), 1},
414 { MS_MAKE_TAG('b','l','w','m'), 1},
415 { MS_MAKE_TAG('a','b','v','m'), 1},
416 { MS_MAKE_TAG('m','k','m','k'), 1},
417 };
418
419 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
420 {
421 { MS_MAKE_TAG('c','c','m','p'), 1},
422 { MS_MAKE_TAG('l','o','c','l'), 1},
423 { MS_MAKE_TAG('c','a','l','t'), 1},
424 { MS_MAKE_TAG('l','i','g','a'), 1},
425 };
426
427 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
428 {
429 { MS_MAKE_TAG('c','c','m','p'), 1},
430 { MS_MAKE_TAG('l','o','c','l'), 1},
431 { MS_MAKE_TAG('c','a','l','t'), 1},
432 { MS_MAKE_TAG('r','l','i','g'), 1},
433 };
434
435 typedef struct ScriptShapeDataTag {
436 TEXTRANGE_PROPERTIES defaultTextRange;
437 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
438 const char *const *requiredFeatures;
439 OPENTYPE_TAG newOtTag;
440 ContextualShapingProc contextProc;
441 ShapeCharGlyphPropProc charGlyphPropProc;
442 } ScriptShapeData;
443
444 /* in order of scripts */
445 static const ScriptShapeData ShapingData[] =
446 {
447 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
448 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
449 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
450 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
451 {{ standard_features, 2}, {NULL, 0}, NULL, 0, ContextualShape_Control, ShapeCharGlyphProp_Control},
452 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
453 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
454 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
455 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
456 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
457 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
458 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
459 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
460 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
461 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
462 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
463 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
464 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
465 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
466 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
467 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
468 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
469 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
470 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
471 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
472 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
473 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
474 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
475 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
476 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
477 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
478 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
479 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
480 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
481 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
482 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
483 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
491 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
492 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
493 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
494 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
495 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
496 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
497 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
498 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
499 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
500 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
501 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
502 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
503 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
504 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
505 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
506 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
510 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
511 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
512 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
513 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
516 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
522 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
523 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
524 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
526 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
527 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
528 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
529 };
530
531 extern scriptData scriptInformation[];
532
533 static int GSUB_apply_feature_all_lookups(const void *header, LoadedFeature *feature,
534 WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count)
535 {
536 int i;
537 int out_index = GSUB_E_NOGLYPH;
538
539 TRACE("%i lookups\n", feature->lookup_count);
540 for (i = 0; i < feature->lookup_count; i++)
541 {
542 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
543 if (out_index != GSUB_E_NOGLYPH)
544 break;
545 }
546 if (out_index == GSUB_E_NOGLYPH)
547 TRACE("lookups found no glyphs\n");
548 else
549 {
550 int out2;
551 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
552 if (out2!=GSUB_E_NOGLYPH)
553 out_index = out2;
554 }
555 return out_index;
556 }
557
558 static OPENTYPE_TAG get_opentype_script(HDC hdc, const SCRIPT_ANALYSIS *psa,
559 const ScriptCache *script_cache, BOOL try_new)
560 {
561 UINT charset;
562
563 if (script_cache->userScript)
564 {
565 if (try_new && ShapingData[psa->eScript].newOtTag
566 && script_cache->userScript == scriptInformation[psa->eScript].scriptTag)
567 return ShapingData[psa->eScript].newOtTag;
568
569 return script_cache->userScript;
570 }
571
572 if (try_new && ShapingData[psa->eScript].newOtTag)
573 return ShapingData[psa->eScript].newOtTag;
574
575 if (scriptInformation[psa->eScript].scriptTag)
576 return scriptInformation[psa->eScript].scriptTag;
577
578 /*
579 * fall back to the font charset
580 */
581 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
582 switch (charset)
583 {
584 case ANSI_CHARSET:
585 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
586 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
587 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
588 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
589 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
590 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
591 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
592 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
593 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
594 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
595 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
596 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
597 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
598 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
599 default: return MS_MAKE_TAG('l','a','t','n');
600 }
601 }
602
603 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
604 {
605 LoadedFeature *feature = NULL;
606
607 if (psc->GSUB_Table || psc->GPOS_Table)
608 {
609 int attempt = 2;
610 OPENTYPE_TAG tags;
611 OPENTYPE_TAG language;
612 OPENTYPE_TAG script = 0x00000000;
613 int cTags;
614
615 do
616 {
617 script = get_opentype_script(hdc,psa,psc,(attempt==2));
618 if (psc->userLang != 0)
619 language = psc->userLang;
620 else
621 language = MS_MAKE_TAG('d','f','l','t');
622 attempt--;
623
624 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
625
626 } while(attempt && !feature);
627
628 /* try in the default (latin) table */
629 if (!feature && !script)
630 OpenType_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
631 }
632
633 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
634 return feature;
635 }
636
637 static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *glyphs, INT index, INT write_dir, INT* glyph_count, const char* feat)
638 {
639 LoadedFeature *feature;
640
641 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
642 if (!feature)
643 return GSUB_E_NOFEATURE;
644
645 TRACE("applying feature %s\n",feat);
646 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
647 }
648
649 static VOID *load_gsub_table(HDC hdc)
650 {
651 VOID* GSUB_Table = NULL;
652 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
653 if (length != GDI_ERROR)
654 {
655 GSUB_Table = heap_alloc(length);
656 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
657 TRACE("Loaded GSUB table of %i bytes\n",length);
658 }
659 return GSUB_Table;
660 }
661
662 static VOID *load_gpos_table(HDC hdc)
663 {
664 VOID* GPOS_Table = NULL;
665 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
666 if (length != GDI_ERROR)
667 {
668 GPOS_Table = heap_alloc(length);
669 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
670 TRACE("Loaded GPOS table of %i bytes\n",length);
671 }
672 return GPOS_Table;
673 }
674
675 static VOID *load_gdef_table(HDC hdc)
676 {
677 VOID* GDEF_Table = NULL;
678 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
679 if (length != GDI_ERROR)
680 {
681 GDEF_Table = heap_alloc(length);
682 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
683 TRACE("Loaded GDEF table of %i bytes\n",length);
684 }
685 return GDEF_Table;
686 }
687
688 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
689 {
690 if (!psc->GSUB_Table)
691 psc->GSUB_Table = load_gsub_table(hdc);
692 if (!psc->GPOS_Table)
693 psc->GPOS_Table = load_gpos_table(hdc);
694 if (!psc->GDEF_Table)
695 psc->GDEF_Table = load_gdef_table(hdc);
696 }
697
698 INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature)
699 {
700 WORD *glyphs;
701 INT glyph_count = count;
702 INT rc;
703
704 glyphs = heap_alloc(2 * count * sizeof(*glyphs));
705 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
706 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
707 if (rc > GSUB_E_NOGLYPH)
708 rc = count - glyph_count;
709 else
710 rc = 0;
711
712 heap_free(glyphs);
713 return rc;
714 }
715
716 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
717 {
718 int i;
719
720 for (i = 0; i < cGlyphs; i++)
721 {
722 if (!pGlyphProp[i].sva.fClusterStart)
723 {
724 int j;
725 for (j = 0; j < cChars; j++)
726 {
727 if (pwLogClust[j] == i)
728 {
729 int k = j;
730 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
731 k-=1;
732 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
733 pwLogClust[j] = pwLogClust[k];
734 }
735 }
736 }
737 }
738 }
739
740 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
741 {
742 if (changeCount == 0)
743 return;
744 else
745 {
746 int cluster_dir = pwLogClust[0] < pwLogClust[chars-1] ? 1 : -1;
747 int i;
748 int target_glyph = nextIndex - write_dir;
749 int target_index = -1;
750 int replacing_glyph = -1;
751 int changed = 0;
752
753 if (changeCount > 0)
754 {
755 if (write_dir > 0)
756 target_glyph = nextIndex - changeCount;
757 else
758 target_glyph = nextIndex + (changeCount + 1);
759 }
760
761 target_index = USP10_FindGlyphInLogClust(pwLogClust, chars, target_glyph);
762 if (target_index == -1)
763 {
764 ERR("Unable to find target glyph\n");
765 return;
766 }
767
768 if (changeCount < 0)
769 {
770 /* merge glyphs */
771 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
772 {
773 if (pwLogClust[i] == target_glyph)
774 continue;
775 if(pwLogClust[i] == replacing_glyph)
776 pwLogClust[i] = target_glyph;
777 else
778 {
779 changed--;
780 if (changed >= changeCount)
781 {
782 replacing_glyph = pwLogClust[i];
783 pwLogClust[i] = target_glyph;
784 }
785 else
786 break;
787 }
788 }
789
790 /* renumber trailing indexes */
791 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
792 {
793 if (pwLogClust[i] != target_glyph)
794 pwLogClust[i] += changeCount;
795 }
796 }
797 else
798 {
799 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
800 pwLogClust[i] += changeCount;
801 }
802 }
803 }
804
805 static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *pwOutGlyphs, int write_dir, INT* pcGlyphs, INT cChars, const char* feat, WORD *pwLogClust )
806 {
807 if (psc->GSUB_Table)
808 {
809 LoadedFeature *feature;
810 int lookup_index;
811
812 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
813 if (!feature)
814 return GSUB_E_NOFEATURE;
815
816 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
817 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
818 {
819 int i;
820
821 if (write_dir > 0)
822 i = 0;
823 else
824 i = *pcGlyphs-1;
825 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
826 while(i < *pcGlyphs && i >= 0)
827 {
828 INT nextIndex;
829 INT prevCount = *pcGlyphs;
830
831 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
832 if (*pcGlyphs != prevCount)
833 {
834 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
835 i = nextIndex;
836 }
837 else
838 i+=write_dir;
839 }
840 }
841 return *pcGlyphs;
842 }
843 return GSUB_E_NOFEATURE;
844 }
845
846 static void GPOS_apply_feature(const ScriptCache *psc, const OUTLINETEXTMETRICW *otm,
847 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance,
848 const LoadedFeature *feature, const WORD *glyphs, int glyph_count, GOFFSET *goffset)
849 {
850 int dir = analysis->fLogicalOrder && analysis->fRTL ? -1 : 1;
851 unsigned int start_idx, i, j;
852
853 TRACE("%i lookups\n", feature->lookup_count);
854
855 start_idx = dir < 0 ? glyph_count - 1 : 0;
856 for (i = 0; i < feature->lookup_count; i++)
857 {
858 for (j = 0; j < glyph_count; )
859 j += OpenType_apply_GPOS_lookup(psc, otm, logfont, analysis, advance,
860 feature->lookups[i], glyphs, start_idx + dir * j, glyph_count, goffset);
861 }
862 }
863
864 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
865 {
866 OPENTYPE_TAG tag;
867 HRESULT hr;
868 int count = 0;
869
870 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
871
872 return(SUCCEEDED(hr));
873 }
874
875 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
876 {
877 int i;
878 for (i = *pcGlyphs; i>=index; i--)
879 pwGlyphs[i+1] = pwGlyphs[i];
880 pwGlyphs[index] = glyph;
881 *pcGlyphs = *pcGlyphs+1;
882 if (write_dir < 0)
883 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
884 else
885 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
886 }
887
888 static void mark_invalid_combinations(HDC hdc, const WCHAR* pwcChars, INT cChars, WORD *pwGlyphs, INT *pcGlyphs, INT write_dir, WORD *pwLogClust, combining_lexical_function lex)
889 {
890 CHAR *context_type;
891 int i,g;
892 WCHAR invalid = 0x25cc;
893 WORD invalid_glyph;
894
895 context_type = heap_alloc(cChars);
896
897 /* Mark invalid combinations */
898 for (i = 0; i < cChars; i++)
899 context_type[i] = lex(pwcChars[i]);
900
901 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
902 for (i = 1, g=1; i < cChars - 1; i++, g++)
903 {
904 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
905 {
906 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
907 g++;
908 }
909 }
910
911 heap_free(context_type);
912 }
913
914 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
915 {
916 int i;
917 for (i=0; i < cChars; i++)
918 {
919 switch (pwcChars[i])
920 {
921 case 0x000A:
922 case 0x000D:
923 pwOutGlyphs[i] = psc->sfp.wgBlank;
924 break;
925 default:
926 if (pwcChars[i] < 0x1C)
927 pwOutGlyphs[i] = psc->sfp.wgDefault;
928 else
929 pwOutGlyphs[i] = psc->sfp.wgBlank;
930 }
931 }
932 }
933
934 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
935 {
936 if (i + delta < 0)
937 return 0;
938 if ( i+ delta >= cchLen)
939 return 0;
940
941 i += delta;
942
943 return chars[i];
944 }
945
946 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
947 {
948 if (i + delta < 0)
949 {
950 if (psa->fLinkBefore)
951 return jtR;
952 else
953 return jtU;
954 }
955 if ( i+ delta >= cchLen)
956 {
957 if (psa->fLinkAfter)
958 return jtL;
959 else
960 return jtU;
961 }
962
963 i += delta;
964
965 if (context_type[i] == jtT)
966 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
967 else
968 return context_type[i];
969 }
970
971 static inline BOOL right_join_causing(CHAR joining_type)
972 {
973 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
974 }
975
976 static inline BOOL left_join_causing(CHAR joining_type)
977 {
978 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
979 }
980
981 static inline BOOL word_break_causing(WCHAR chr)
982 {
983 /* we are working within a string of characters already guareented to
984 be within one script, Syriac, so we do not worry about any character
985 other than the space character outside of that range */
986 return (chr == 0 || chr == 0x20 );
987 }
988
989 static int combining_lexical_Arabic(WCHAR c)
990 {
991 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
992
993 switch(c)
994 {
995 case 0x064B:
996 case 0x064C:
997 case 0x064E:
998 case 0x064F:
999 case 0x0652:
1000 case 0x0657:
1001 case 0x0658:
1002 case 0x06E1: return Arab_DIAC1;
1003 case 0x064D:
1004 case 0x0650:
1005 case 0x0656: return Arab_DIAC2;
1006 case 0x0651: return Arab_DIAC3;
1007 case 0x0610:
1008 case 0x0611:
1009 case 0x0612:
1010 case 0x0613:
1011 case 0x0614:
1012 case 0x0659:
1013 case 0x06D6:
1014 case 0x06DC:
1015 case 0x06DF:
1016 case 0x06E0:
1017 case 0x06E2:
1018 case 0x06E4:
1019 case 0x06E7:
1020 case 0x06E8:
1021 case 0x06EB:
1022 case 0x06EC: return Arab_DIAC4;
1023 case 0x06E3:
1024 case 0x06EA:
1025 case 0x06ED: return Arab_DIAC5;
1026 case 0x0670: return Arab_DIAC6;
1027 case 0x0653: return Arab_DIAC7;
1028 case 0x0655:
1029 case 0x0654: return Arab_DIAC8;
1030 default: return Arab_Norm;
1031 }
1032 }
1033
1034 /*
1035 * ContextualShape_Arabic
1036 */
1037 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1038 {
1039 CHAR *context_type;
1040 INT *context_shape;
1041 INT dirR, dirL;
1042 int i;
1043 int char_index;
1044 int glyph_index;
1045
1046 if (*pcGlyphs != cChars)
1047 {
1048 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1049 return;
1050 }
1051
1052 if (psa->fLogicalOrder && psa->fRTL)
1053 {
1054 dirR = -1;
1055 dirL = 1;
1056 }
1057 else
1058 {
1059 dirR = 1;
1060 dirL = -1;
1061 }
1062
1063 load_ot_tables(hdc, psc);
1064
1065 context_type = heap_alloc(cChars);
1066 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1067
1068 for (i = 0; i < cChars; i++)
1069 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1070
1071 for (i = 0; i < cChars; i++)
1072 {
1073 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1074 context_shape[i] = Xr;
1075 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1076 context_shape[i] = Xl;
1077 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)) && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1078 context_shape[i] = Xm;
1079 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1080 context_shape[i] = Xr;
1081 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1082 context_shape[i] = Xl;
1083 else
1084 context_shape[i] = Xn;
1085 }
1086
1087 /* Contextual Shaping */
1088 if (dirL > 0)
1089 char_index = glyph_index = 0;
1090 else
1091 char_index = glyph_index = cChars-1;
1092
1093 while(char_index < cChars && char_index >= 0)
1094 {
1095 BOOL shaped = FALSE;
1096
1097 if (psc->GSUB_Table)
1098 {
1099 INT nextIndex, offset = 0;
1100 INT prevCount = *pcGlyphs;
1101
1102 /* Apply CCMP first */
1103 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1104
1105 if (prevCount != *pcGlyphs)
1106 {
1107 offset = *pcGlyphs - prevCount;
1108 if (dirL < 0)
1109 glyph_index -= offset * dirL;
1110 }
1111
1112 /* Apply the contextual feature */
1113 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1114
1115 if (nextIndex > GSUB_E_NOGLYPH)
1116 {
1117 UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1118 char_index += dirL;
1119 if (!offset)
1120 glyph_index = nextIndex;
1121 else
1122 {
1123 offset = *pcGlyphs - prevCount;
1124 glyph_index += dirL * (offset + 1);
1125 }
1126 shaped = TRUE;
1127 }
1128 else if (nextIndex == GSUB_E_NOGLYPH)
1129 {
1130 char_index += dirL;
1131 glyph_index += dirL;
1132 shaped = TRUE;
1133 }
1134 }
1135
1136 if (!shaped)
1137 {
1138 if (context_shape[char_index] == Xn)
1139 {
1140 WORD newGlyph = pwOutGlyphs[glyph_index];
1141 if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
1142 {
1143 /* fall back to presentation form B */
1144 WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
1145 if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1146 pwOutGlyphs[glyph_index] = newGlyph;
1147 }
1148 }
1149 char_index += dirL;
1150 glyph_index += dirL;
1151 }
1152 }
1153
1154 heap_free(context_shape);
1155 heap_free(context_type);
1156
1157 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1158 }
1159
1160 static int combining_lexical_Hebrew(WCHAR c)
1161 {
1162 enum {Hebr_Norm=0, Hebr_DIAC, Hebr_CANT1, Hebr_CANT2, Hebr_CANT3, Hebr_CANT4, Hebr_CANT5, Hebr_CANT6, Hebr_CANT7, Hebr_CANT8, Hebr_CANT9, Hebr_CANT10, Hebr_DAGESH, Hebr_DOTABV, Hebr_HOLAM, Hebr_METEG, Hebr_PATAH, Hebr_QAMATS, Hebr_RAFE, Hebr_SHINSIN};
1163
1164 switch(c)
1165 {
1166 case 0x05B0:
1167 case 0x05B1:
1168 case 0x05B2:
1169 case 0x05B3:
1170 case 0x05B4:
1171 case 0x05B5:
1172 case 0x05B6:
1173 case 0x05BB: return Hebr_DIAC;
1174 case 0x0599:
1175 case 0x05A1:
1176 case 0x05A9:
1177 case 0x05AE: return Hebr_CANT1;
1178 case 0x0597:
1179 case 0x05A8:
1180 case 0x05AC: return Hebr_CANT2;
1181 case 0x0592:
1182 case 0x0593:
1183 case 0x0594:
1184 case 0x0595:
1185 case 0x05A7:
1186 case 0x05AB: return Hebr_CANT3;
1187 case 0x0598:
1188 case 0x059C:
1189 case 0x059E:
1190 case 0x059F: return Hebr_CANT4;
1191 case 0x059D:
1192 case 0x05A0: return Hebr_CANT5;
1193 case 0x059B:
1194 case 0x05A5: return Hebr_CANT6;
1195 case 0x0591:
1196 case 0x05A3:
1197 case 0x05A6: return Hebr_CANT7;
1198 case 0x0596:
1199 case 0x05A4:
1200 case 0x05AA: return Hebr_CANT8;
1201 case 0x059A:
1202 case 0x05AD: return Hebr_CANT9;
1203 case 0x05AF: return Hebr_CANT10;
1204 case 0x05BC: return Hebr_DAGESH;
1205 case 0x05C4: return Hebr_DOTABV;
1206 case 0x05B9: return Hebr_HOLAM;
1207 case 0x05BD: return Hebr_METEG;
1208 case 0x05B7: return Hebr_PATAH;
1209 case 0x05B8: return Hebr_QAMATS;
1210 case 0x05BF: return Hebr_RAFE;
1211 case 0x05C1:
1212 case 0x05C2: return Hebr_SHINSIN;
1213 default: return Hebr_Norm;
1214 }
1215 }
1216
1217 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1218 {
1219 INT dirL;
1220
1221 if (*pcGlyphs != cChars)
1222 {
1223 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1224 return;
1225 }
1226
1227 if (!psa->fLogicalOrder && psa->fRTL)
1228 dirL = -1;
1229 else
1230 dirL = 1;
1231
1232 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1233 }
1234
1235 /*
1236 * ContextualShape_Syriac
1237 */
1238
1239 static int combining_lexical_Syriac(WCHAR c)
1240 {
1241 enum {Syriac_Norm=0, Syriac_DIAC1, Syriac_DIAC2, Syriac_DIAC3, Syriac_DIAC4, Syriac_DIAC5, Syriac_DIAC6, Syriac_DIAC7, Syriac_DIAC8, Syriac_DIAC9, Syriac_DIAC10, Syriac_DIAC11, Syriac_DIAC12, Syriac_DIAC13, Syriac_DIAC14, Syriac_DIAC15, Syriac_DIAC16, Syriac_DIAC17};
1242
1243 switch(c)
1244 {
1245 case 0x730:
1246 case 0x733:
1247 case 0x736:
1248 case 0x73A:
1249 case 0x73D: return Syriac_DIAC1;
1250 case 0x731:
1251 case 0x734:
1252 case 0x737:
1253 case 0x73B:
1254 case 0x73E: return Syriac_DIAC2;
1255 case 0x740:
1256 case 0x749:
1257 case 0x74A: return Syriac_DIAC3;
1258 case 0x732:
1259 case 0x735:
1260 case 0x73F: return Syriac_DIAC4;
1261 case 0x738:
1262 case 0x739:
1263 case 0x73C: return Syriac_DIAC5;
1264 case 0x741:
1265 case 0x30A: return Syriac_DIAC6;
1266 case 0x742:
1267 case 0x325: return Syriac_DIAC7;
1268 case 0x747:
1269 case 0x303: return Syriac_DIAC8;
1270 case 0x748:
1271 case 0x32D:
1272 case 0x32E:
1273 case 0x330:
1274 case 0x331: return Syriac_DIAC9;
1275 case 0x308: return Syriac_DIAC10;
1276 case 0x304: return Syriac_DIAC11;
1277 case 0x307: return Syriac_DIAC12;
1278 case 0x323: return Syriac_DIAC13;
1279 case 0x743: return Syriac_DIAC14;
1280 case 0x744: return Syriac_DIAC15;
1281 case 0x745: return Syriac_DIAC16;
1282 case 0x746: return Syriac_DIAC17;
1283 default: return Syriac_Norm;
1284 }
1285 }
1286
1287 #define ALAPH 0x710
1288 #define DALATH 0x715
1289 #define RISH 0x72A
1290
1291 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1292 {
1293 CHAR *context_type;
1294 INT *context_shape;
1295 INT dirR, dirL;
1296 int i;
1297 int char_index;
1298 int glyph_index;
1299
1300 if (*pcGlyphs != cChars)
1301 {
1302 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1303 return;
1304 }
1305
1306 if (!psa->fLogicalOrder && psa->fRTL)
1307 {
1308 dirR = 1;
1309 dirL = -1;
1310 }
1311 else
1312 {
1313 dirR = -1;
1314 dirL = 1;
1315 }
1316
1317 load_ot_tables(hdc, psc);
1318
1319 if (!psc->GSUB_Table)
1320 return;
1321
1322 context_type = heap_alloc(cChars);
1323 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1324
1325 for (i = 0; i < cChars; i++)
1326 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1327
1328 for (i = 0; i < cChars; i++)
1329 {
1330 if (pwcChars[i] == ALAPH)
1331 {
1332 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1333
1334 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1335 context_shape[i] = Afj;
1336 else if ( rchar != DALATH && rchar != RISH &&
1337 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1338 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1339 context_shape[i] = Afn;
1340 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1341 context_shape[i] = Afx;
1342 else
1343 context_shape[i] = Xn;
1344 }
1345 else if (context_type[i] == jtR &&
1346 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1347 context_shape[i] = Xr;
1348 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1349 context_shape[i] = Xl;
1350 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)) && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1351 context_shape[i] = Xm;
1352 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1353 context_shape[i] = Xr;
1354 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1355 context_shape[i] = Xl;
1356 else
1357 context_shape[i] = Xn;
1358 }
1359
1360 /* Contextual Shaping */
1361 if (dirL > 0)
1362 char_index = glyph_index = 0;
1363 else
1364 char_index = glyph_index = cChars-1;
1365
1366 while(char_index < cChars && char_index >= 0)
1367 {
1368 INT nextIndex, offset = 0;
1369 INT prevCount = *pcGlyphs;
1370
1371 /* Apply CCMP first */
1372 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1373
1374 if (prevCount != *pcGlyphs)
1375 {
1376 offset = *pcGlyphs - prevCount;
1377 if (dirL < 0)
1378 glyph_index -= offset * dirL;
1379 }
1380
1381 /* Apply the contextual feature */
1382 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1383 if (nextIndex > GSUB_E_NOGLYPH)
1384 {
1385 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1386 char_index += dirL;
1387 if (!offset)
1388 glyph_index = nextIndex;
1389 else
1390 {
1391 offset = *pcGlyphs - prevCount;
1392 glyph_index += dirL * (offset + 1);
1393 }
1394 }
1395 else
1396 {
1397 char_index += dirL;
1398 glyph_index += dirL;
1399 }
1400 }
1401
1402 heap_free(context_shape);
1403 heap_free(context_type);
1404
1405 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1406 }
1407
1408 static int combining_lexical_Thaana(WCHAR c)
1409 {
1410 enum {Thaana_Norm=0, Thaana_FILI};
1411
1412 switch(c)
1413 {
1414 case 0x7A6:
1415 case 0x7A7:
1416 case 0x7A8:
1417 case 0x7A9:
1418 case 0x7AA:
1419 case 0x7AB:
1420 case 0x7AC:
1421 case 0x7AD:
1422 case 0x7AE:
1423 case 0x7AF: return Thaana_FILI;
1424 default: return Thaana_Norm;
1425 }
1426 }
1427
1428 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1429 {
1430 INT dirL;
1431
1432 if (*pcGlyphs != cChars)
1433 {
1434 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1435 return;
1436 }
1437
1438 if (!psa->fLogicalOrder && psa->fRTL)
1439 dirL = -1;
1440 else
1441 dirL = 1;
1442
1443 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1444 }
1445
1446 /*
1447 * ContextualShape_Phags_pa
1448 */
1449
1450 #define phags_pa_CANDRABINDU 0xA873
1451 #define phags_pa_START 0xA840
1452 #define phags_pa_END 0xA87F
1453
1454 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1455 {
1456 INT *context_shape;
1457 INT dirR, dirL;
1458 int i;
1459 int char_index;
1460 int glyph_index;
1461
1462 if (*pcGlyphs != cChars)
1463 {
1464 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1465 return;
1466 }
1467
1468 if (!psa->fLogicalOrder && psa->fRTL)
1469 {
1470 dirR = 1;
1471 dirL = -1;
1472 }
1473 else
1474 {
1475 dirR = -1;
1476 dirL = 1;
1477 }
1478
1479 load_ot_tables(hdc, psc);
1480
1481 if (!psc->GSUB_Table)
1482 return;
1483
1484 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1485
1486 for (i = 0; i < cChars; i++)
1487 {
1488 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1489 {
1490 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1491 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1492 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1493 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1494
1495 if (jrchar && jlchar)
1496 context_shape[i] = Xm;
1497 else if (jrchar)
1498 context_shape[i] = Xr;
1499 else if (jlchar)
1500 context_shape[i] = Xl;
1501 else
1502 context_shape[i] = Xn;
1503 }
1504 else
1505 context_shape[i] = -1;
1506 }
1507
1508 /* Contextual Shaping */
1509 if (dirL > 0)
1510 char_index = glyph_index = 0;
1511 else
1512 char_index = glyph_index = cChars-1;
1513
1514 while(char_index < cChars && char_index >= 0)
1515 {
1516 if (context_shape[char_index] >= 0)
1517 {
1518 INT nextIndex;
1519 INT prevCount = *pcGlyphs;
1520 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1521
1522 if (nextIndex > GSUB_E_NOGLYPH)
1523 {
1524 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1525 glyph_index = nextIndex;
1526 char_index += dirL;
1527 }
1528 else
1529 {
1530 char_index += dirL;
1531 glyph_index += dirL;
1532 }
1533 }
1534 else
1535 {
1536 char_index += dirL;
1537 glyph_index += dirL;
1538 }
1539 }
1540
1541 heap_free(context_shape);
1542 }
1543
1544 static int combining_lexical_Thai(WCHAR c)
1545 {
1546 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1547
1548 switch(c)
1549 {
1550 case 0xE31:
1551 case 0xE34:
1552 case 0xE35:
1553 case 0xE36:
1554 case 0xE37: return Thai_ABOVE1;
1555 case 0xE47:
1556 case 0xE4D: return Thai_ABOVE2;
1557 case 0xE48:
1558 case 0xE49:
1559 case 0xE4A:
1560 case 0xE4B: return Thai_ABOVE3;
1561 case 0xE4C:
1562 case 0xE4E: return Thai_ABOVE4;
1563 case 0xE38:
1564 case 0xE39: return Thai_BELOW1;
1565 case 0xE3A: return Thai_BELOW2;
1566 case 0xE33: return Thai_AM;
1567 default: return Thai_Norm;
1568 }
1569 }
1570
1571 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1572 {
1573 INT dirL;
1574
1575 if (*pcGlyphs != cChars)
1576 {
1577 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1578 return;
1579 }
1580
1581 if (!psa->fLogicalOrder && psa->fRTL)
1582 dirL = -1;
1583 else
1584 dirL = 1;
1585
1586 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1587 }
1588
1589 static int combining_lexical_Lao(WCHAR c)
1590 {
1591 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1592
1593 switch(c)
1594 {
1595 case 0xEB1:
1596 case 0xEB4:
1597 case 0xEB5:
1598 case 0xEB6:
1599 case 0xEB7:
1600 case 0xEBB:
1601 case 0xECD: return Lao_ABOVE1;
1602 case 0xEC8:
1603 case 0xEC9:
1604 case 0xECA:
1605 case 0xECB:
1606 case 0xECC: return Lao_ABOVE2;
1607 case 0xEBC: return Lao_BELOW1;
1608 case 0xEB8:
1609 case 0xEB9: return Lao_BELOW2;
1610 case 0xEB3: return Lao_AM;
1611 default: return Lao_Norm;
1612 }
1613 }
1614
1615 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1616 {
1617 INT dirL;
1618
1619 if (*pcGlyphs != cChars)
1620 {
1621 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1622 return;
1623 }
1624
1625 if (!psa->fLogicalOrder && psa->fRTL)
1626 dirL = -1;
1627 else
1628 dirL = 1;
1629
1630 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1631 }
1632
1633 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1634 {
1635 int i;
1636
1637 /* Replace */
1638 pwOutChars[cWalk] = replacements[0];
1639 cWalk=cWalk+1;
1640
1641 /* Insert */
1642 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1643 {
1644 int j;
1645 for (j = *pcChars; j > cWalk; j--)
1646 pwOutChars[j] = pwOutChars[j-1];
1647 *pcChars= *pcChars+1;
1648 pwOutChars[cWalk] = replacements[i];
1649 cWalk = cWalk+1;
1650 }
1651 }
1652
1653 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1654 {
1655 int i;
1656 int cWalk;
1657
1658 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1659 {
1660 for (i = 0; vowels[i].base != 0x0; i++)
1661 {
1662 if (pwOutChars[cWalk] == vowels[i].base)
1663 {
1664 int o = 0;
1665 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1666 if (vowels[i].parts[1]) { cWalk++; o++; }
1667 if (vowels[i].parts[2]) { cWalk++; o++; }
1668 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1669 break;
1670 }
1671 }
1672 }
1673 }
1674
1675 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1676 {
1677 int i;
1678 int offset = 0;
1679 int cWalk;
1680
1681 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1682 {
1683 for (i = 0; consonants[i].output!= 0x0; i++)
1684 {
1685 int j;
1686 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1687 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1688 break;
1689
1690 if (consonants[i].parts[j]==0x0) /* matched all */
1691 {
1692 int k;
1693 j--;
1694 pwOutChars[cWalk] = consonants[i].output;
1695 for(k = cWalk+1; k < *pcChars - j; k++)
1696 pwOutChars[k] = pwOutChars[k+j];
1697 *pcChars = *pcChars - j;
1698 for (k = j ; k > 0; k--)
1699 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1700 offset += j;
1701 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1702 pwLogClust[k]--;
1703 break;
1704 }
1705 }
1706 cWalk++;
1707 }
1708 }
1709
1710 static void Reorder_Ra_follows_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1711 {
1712 if (s->ralf >= 0)
1713 {
1714 int j;
1715 WORD Ra = pwChar[s->start];
1716 WORD H = pwChar[s->start+1];
1717
1718 TRACE("Doing reorder of Ra to %i\n",s->base);
1719 for (j = s->start; j < s->base-1; j++)
1720 pwChar[j] = pwChar[j+2];
1721 pwChar[s->base-1] = Ra;
1722 pwChar[s->base] = H;
1723
1724 s->ralf = s->base-1;
1725 s->base -= 2;
1726 }
1727 }
1728
1729 static void Reorder_Ra_follows_matra(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1730 {
1731 if (s->ralf >= 0)
1732 {
1733 int j,loc;
1734 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1735 WORD Ra = pwChar[s->start];
1736 WORD H = pwChar[s->start+1];
1737 for (loc = s->end; loc > stop; loc--)
1738 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1739 break;
1740
1741 TRACE("Doing reorder of Ra to %i\n",loc);
1742 for (j = s->start; j < loc-1; j++)
1743 pwChar[j] = pwChar[j+2];
1744 pwChar[loc-1] = Ra;
1745 pwChar[loc] = H;
1746
1747 s->ralf = loc-1;
1748 s->base -= 2;
1749 if (s->blwf >= 0) s->blwf -= 2;
1750 if (s->pref >= 0) s->pref -= 2;
1751 }
1752 }
1753
1754 static void Reorder_Ra_follows_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1755 {
1756 if (s->ralf >= 0)
1757 {
1758 int j;
1759 WORD Ra = pwChar[s->start];
1760 WORD H = pwChar[s->start+1];
1761
1762 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1763 for (j = s->start; j < s->end-1; j++)
1764 pwChar[j] = pwChar[j+2];
1765 pwChar[s->end-1] = Ra;
1766 pwChar[s->end] = H;
1767
1768 s->ralf = s->end-1;
1769 s->base -= 2;
1770 if (s->blwf >= 0) s->blwf -= 2;
1771 if (s->pref >= 0) s->pref -= 2;
1772 }
1773 }
1774
1775 static void Reorder_Matra_precede_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1776 {
1777 int i;
1778
1779 /* reorder Matras */
1780 if (s->end > s->base)
1781 {
1782 for (i = 1; i <= s->end-s->base; i++)
1783 {
1784 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1785 {
1786 int j;
1787 WCHAR c = pwChar[s->base+i];
1788 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1789 for (j = s->base+i; j > s->base; j--)
1790 pwChar[j] = pwChar[j-1];
1791 pwChar[s->base] = c;
1792
1793 if (s->ralf >= s->base) s->ralf++;
1794 if (s->blwf >= s->base) s->blwf++;
1795 if (s->pref >= s->base) s->pref++;
1796 s->base ++;
1797 }
1798 }
1799 }
1800 }
1801
1802 static void Reorder_Matra_precede_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1803 {
1804 int i;
1805
1806 /* reorder Matras */
1807 if (s->end > s->base)
1808 {
1809 for (i = 1; i <= s->end-s->base; i++)
1810 {
1811 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1812 {
1813 int j;
1814 WCHAR c = pwChar[s->base+i];
1815 TRACE("Doing reorder of %x to %i\n",c,s->start);
1816 for (j = s->base+i; j > s->start; j--)
1817 pwChar[j] = pwChar[j-1];
1818 pwChar[s->start] = c;
1819
1820 if (s->ralf >= 0) s->ralf++;
1821 if (s->blwf >= 0) s->blwf++;
1822 if (s->pref >= 0) s->pref++;
1823 s->base ++;
1824 }
1825 }
1826 }
1827 }
1828
1829 static void SecondReorder_Blwf_follows_matra(const WCHAR *chars, const IndicSyllable *s,
1830 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1831 {
1832 if (s->blwf >= 0 && g->blwf > g->base)
1833 {
1834 int j,loc;
1835 int g_offset;
1836 for (loc = s->end; loc > s->blwf; loc--)
1837 if (lexical(chars[loc]) == lex_Matra_below || lexical(chars[loc]) == lex_Matra_above
1838 || lexical(chars[loc]) == lex_Matra_post)
1839 break;
1840
1841 g_offset = (loc - s->blwf) - 1;
1842
1843 if (loc != s->blwf)
1844 {
1845 WORD blwf = glyphs[g->blwf];
1846 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1847 /* do not care about the pwChar array anymore, just the glyphs */
1848 for (j = 0; j < g_offset; j++)
1849 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1850 glyphs[g->blwf + g_offset] = blwf;
1851 }
1852 }
1853 }
1854
1855 static void SecondReorder_Matra_precede_base(const WCHAR *chars, const IndicSyllable *s,
1856 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1857 {
1858 int i;
1859
1860 /* reorder previously moved Matras to correct position*/
1861 for (i = s->start; i < s->base; i++)
1862 {
1863 if (lexical(chars[i]) == lex_Matra_pre)
1864 {
1865 int j;
1866 int g_start = g->start + i - s->start;
1867 if (g_start < g->base -1 )
1868 {
1869 WCHAR og = glyphs[g_start];
1870 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1871 for (j = g_start; j < g->base-1; j++)
1872 glyphs[j] = glyphs[j+1];
1873 glyphs[g->base-1] = og;
1874 }
1875 }
1876 }
1877 }
1878
1879 static void SecondReorder_Pref_precede_base(const IndicSyllable *s,
1880 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1881 {
1882 if (s->pref >= 0 && g->pref > g->base)
1883 {
1884 int j;
1885 WCHAR og = glyphs[g->pref];
1886 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1887 for (j = g->pref; j > g->base; j--)
1888 glyphs[j] = glyphs[j-1];
1889 glyphs[g->base] = og;
1890 }
1891 }
1892
1893 static void Reorder_Like_Sinhala(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1894 {
1895 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1896 if (s->start == s->base && s->base == s->end) return;
1897 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1898
1899 Reorder_Ra_follows_base(pwChar, s, lexical);
1900 Reorder_Matra_precede_base(pwChar, s, lexical);
1901 }
1902
1903 static void Reorder_Like_Devanagari(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1904 {
1905 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1906 if (s->start == s->base && s->base == s->end) return;
1907 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1908
1909 Reorder_Ra_follows_matra(pwChar, s, lexical);
1910 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1911 }
1912
1913 static void Reorder_Like_Bengali(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1914 {
1915 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1916 if (s->start == s->base && s->base == s->end) return;
1917 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1918
1919 Reorder_Ra_follows_base(pwChar, s, lexical);
1920 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1921 }
1922
1923 static void Reorder_Like_Kannada(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1924 {
1925 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1926 if (s->start == s->base && s->base == s->end) return;
1927 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1928
1929 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1930 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1931 }
1932
1933 static void SecondReorder_Like_Telugu(const WCHAR *chars, const IndicSyllable *s,
1934 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1935 {
1936 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1937 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1938 if (s->start == s->base && s->base == s->end) return;
1939 if (lexical(chars[s->base]) == lex_Vowel) return;
1940
1941 SecondReorder_Blwf_follows_matra(chars, s, glyphs, g, lexical);
1942 }
1943
1944 static void SecondReorder_Like_Tamil(const WCHAR *chars, const IndicSyllable *s,
1945 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1946 {
1947 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1948 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1949 if (s->start == s->base && s->base == s->end) return;
1950 if (lexical(chars[s->base]) == lex_Vowel) return;
1951
1952 SecondReorder_Matra_precede_base(chars, s, glyphs, g, lexical);
1953 SecondReorder_Pref_precede_base(s, glyphs, g, lexical);
1954 }
1955
1956
1957 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1958 {
1959 if (shift == 0)
1960 return;
1961
1962 if (glyph_index->start > index)
1963 glyph_index->start += shift;
1964 if (glyph_index->base > index)
1965 glyph_index->base+= shift;
1966 if (glyph_index->end > index)
1967 glyph_index->end+= shift;
1968 if (glyph_index->ralf > index)
1969 glyph_index->ralf+= shift;
1970 if (glyph_index->blwf > index)
1971 glyph_index->blwf+= shift;
1972 if (glyph_index->pref > index)
1973 glyph_index->pref+= shift;
1974 }
1975
1976 static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, LoadedFeature *feature )
1977 {
1978 int index = glyph_index->start;
1979
1980 if (!feature)
1981 return;
1982
1983 while(index <= glyph_index->end)
1984 {
1985 INT nextIndex;
1986 INT prevCount = *pcGlyphs;
1987 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1988 if (nextIndex > GSUB_E_NOGLYPH)
1989 {
1990 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1991 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1992 index = nextIndex;
1993 }
1994 else
1995 index++;
1996 }
1997 }
1998
1999 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2000 {
2001 int i = 0;
2002 while (i + index < end - 1 && !(is_consonant(lexical(pwChars[index+i])) && (lexical(pwChars[index+i+1]) == lex_Halant || (index + i < end - 2 && lexical(pwChars[index+i+1]) == lex_Nukta && lexical(pwChars[index+i+2] == lex_Halant)))))
2003 i++;
2004 if (index + i <= end-1)
2005 return index + i;
2006 else
2007 return -1;
2008 }
2009
2010 static void Apply_Indic_PreBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const char* feature)
2011 {
2012 INT index, nextIndex;
2013 INT count,g_offset;
2014
2015 count = syllable->base - syllable->start;
2016
2017 g_offset = 0;
2018 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2019 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2020 {
2021 INT prevCount = *pcGlyphs;
2022 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2023 if (nextIndex > GSUB_E_NOGLYPH)
2024 {
2025 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2026 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2027 g_offset += (*pcGlyphs - prevCount);
2028 }
2029
2030 index+=2;
2031 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2032 }
2033 }
2034
2035 static void Apply_Indic_Rphf(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index)
2036 {
2037 INT nextIndex;
2038 INT prevCount = *pcGlyphs;
2039
2040 if (syllable->ralf >= 0)
2041 {
2042 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2043 if (nextIndex > GSUB_E_NOGLYPH)
2044 {
2045 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2046 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2047 }
2048 }
2049 }
2050
2051 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2052 {
2053 int i = 0;
2054 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2055 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2056 is_consonant(lexical(pwChars[index+i+1])))))
2057 i++;
2058 if (index + i <= end-1)
2059 return index+i;
2060 else
2061 return -1;
2062 }
2063
2064 static void Apply_Indic_PostBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, BOOL modern, const char* feat)
2065 {
2066 INT index, nextIndex;
2067 INT count, g_offset=0;
2068 INT ralf = syllable->ralf;
2069
2070 count = syllable->end - syllable->base;
2071
2072 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2073
2074 while (index >= 0)
2075 {
2076 INT prevCount = *pcGlyphs;
2077 if (ralf >=0 && ralf < index)
2078 {
2079 g_offset--;
2080 ralf = -1;
2081 }
2082
2083 if (!modern)
2084 {
2085 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2086 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2087 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2088 }
2089
2090 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2091 if (nextIndex > GSUB_E_NOGLYPH)
2092 {
2093 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2094 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2095 g_offset += (*pcGlyphs - prevCount);
2096 }
2097 else if (!modern)
2098 {
2099 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2100 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2101 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2102 }
2103
2104 index+=2;
2105 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2106 }
2107 }
2108
2109 static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllables, INT syllable_count, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, second_reorder_function second_reorder, BOOL modern)
2110 {
2111 int c;
2112 int overall_shift = 0;
2113 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2114 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2115 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2116 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2117 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2118 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2119 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2120 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2121 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2122 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2123 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2124 IndicSyllable glyph_indexs;
2125
2126 for (c = 0; c < syllable_count; c++)
2127 {
2128 int old_end;
2129 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2130 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2131 old_end = glyph_indexs.end;
2132
2133 if (locl)
2134 {
2135 TRACE("applying feature locl\n");
2136 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2137 }
2138 if (nukt)
2139 {
2140 TRACE("applying feature nukt\n");
2141 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2142 }
2143 if (akhn)
2144 {
2145 TRACE("applying feature akhn\n");
2146 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2147 }
2148
2149 if (rphf)
2150 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2151 if (rkrf)
2152 {
2153 TRACE("applying feature rkrf\n");
2154 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2155 }
2156 if (pref)
2157 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2158 if (blwf)
2159 {
2160 if (!modern)
2161 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2162
2163 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2164
2165 }
2166 if (half)
2167 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2168 if (pstf)
2169 {
2170 TRACE("applying feature pstf\n");
2171 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2172 }
2173 if (vatu)
2174 {
2175 TRACE("applying feature vatu\n");
2176 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2177 }
2178 if (cjct)
2179 {
2180 TRACE("applying feature cjct\n");
2181 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2182 }
2183
2184 if (second_reorder)
2185 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2186
2187 overall_shift += glyph_indexs.end - old_end;
2188 }
2189 }
2190
2191 static inline int unicode_lex(WCHAR c)
2192 {
2193 int type;
2194
2195 if (!c) return lex_Generic;
2196 if (c == 0x200D) return lex_ZWJ;
2197 if (c == 0x200C) return lex_ZWNJ;
2198 if (c == 0x00A0) return lex_NBSP;
2199
2200 type = get_table_entry( indic_syllabic_table, c );
2201
2202 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2203
2204 switch( type )
2205 {
2206 case 0x0d07: /* Unknown */
2207 case 0x0e07: /* Unknown */
2208 default: return lex_Generic;
2209 case 0x0001:
2210 case 0x0002:
2211 case 0x0011:
2212 case 0x0012:
2213 case 0x0013:
2214 case 0x0014: return lex_Modifier;
2215 case 0x0003:
2216 case 0x0009:
2217 case 0x000a:
2218 case 0x000b:
2219 case 0x000d:
2220 case 0x000e:
2221 case 0x000f:
2222 case 0x0010: return lex_Consonant;
2223 case 0x0004: return lex_Nukta;
2224 case 0x0005: return lex_Halant;
2225 case 0x0006:
2226 case 0x0008: return lex_Vowel;
2227 case 0x0007:
2228 case 0x0107: return lex_Matra_post;
2229 case 0x0207:
2230 case 0x0307: return lex_Matra_pre;
2231 case 0x0807:
2232 case 0x0907:
2233 case 0x0a07:
2234 case 0x0b07:
2235 case 0x0c07:
2236 case 0x0407: return lex_Composed_Vowel;
2237 case 0x0507: return lex_Matra_above;
2238 case 0x0607: return lex_Matra_below;
2239 case 0x000c:
2240 case 0x0015: return lex_Ra;
2241 };
2242 }
2243
2244 static int sinhala_lex(WCHAR c)
2245 {
2246 switch (c)
2247 {
2248 case 0x0DDA:
2249 case 0x0DDD:
2250 case 0x0DDC:
2251 case 0x0DDE: return lex_Matra_post;
2252 default:
2253 return unicode_lex(c);
2254 }
2255 }
2256
2257 static const VowelComponents Sinhala_vowels[] = {
2258 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2259 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2260 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2261 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2262 {0x0000, {0x0000,0x0000,0x0}}};
2263
2264 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2265 {
2266 int cCount = cChars;
2267 int i;
2268 WCHAR *input;
2269 IndicSyllable *syllables = NULL;
2270 int syllable_count = 0;
2271
2272 if (*pcGlyphs != cChars)
2273 {
2274 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2275 return;
2276 }
2277
2278 input = heap_alloc(3 * cChars * sizeof(*input));
2279
2280 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2281
2282 /* Step 1: Decompose multi part vowels */
2283 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2284
2285 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2286
2287 /* Step 2: Reorder within Syllables */
2288 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2289 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2290
2291 /* Step 3: Strip dangling joiners */
2292 for (i = 0; i < cCount; i++)
2293 {
2294 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2295 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2296 input[i] = 0x0020;
2297 }
2298
2299 /* Step 4: Base Form application to syllables */
2300 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2301 *pcGlyphs = cCount;
2302 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2303
2304 heap_free(input);
2305 heap_free(syllables);
2306 }
2307
2308 static int devanagari_lex(WCHAR c)
2309 {
2310 switch (c)
2311 {
2312 case 0x0930: return lex_Ra;
2313 default:
2314 return unicode_lex(c);
2315 }
2316 }
2317
2318 static const ConsonantComponents Devanagari_consonants[] ={
2319 {{0x0928, 0x093C, 0x00000}, 0x0929},
2320 {{0x0930, 0x093C, 0x00000}, 0x0931},
2321 {{0x0933, 0x093C, 0x00000}, 0x0934},
2322 {{0x0915, 0x093C, 0x00000}, 0x0958},
2323 {{0x0916, 0x093C, 0x00000}, 0x0959},
2324 {{0x0917, 0x093C, 0x00000}, 0x095A},
2325 {{0x091C, 0x093C, 0x00000}, 0x095B},
2326 {{0x0921, 0x093C, 0x00000}, 0x095C},
2327 {{0x0922, 0x093C, 0x00000}, 0x095D},
2328 {{0x092B, 0x093C, 0x00000}, 0x095E},
2329 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2330
2331 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2332 {
2333 int cCount = cChars;
2334 WCHAR *input;
2335 IndicSyllable *syllables = NULL;
2336 int syllable_count = 0;
2337 BOOL modern = get_GSUB_Indic2(psa, psc);
2338
2339 if (*pcGlyphs != cChars)
2340 {
2341 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2342 return;
2343 }
2344
2345 input = heap_alloc(cChars * sizeof(*input));
2346 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2347
2348 /* Step 1: Compose Consonant and Nukta */
2349 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2350 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2351
2352 /* Step 2: Reorder within Syllables */
2353 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2354 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2355 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2356 *pcGlyphs = cCount;
2357
2358 /* Step 3: Base Form application to syllables */
2359 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2360
2361 heap_free(input);
2362 heap_free(syllables);
2363 }
2364
2365 static int bengali_lex(WCHAR c)
2366 {
2367 switch (c)
2368 {
2369 case 0x09B0: return lex_Ra;
2370 default:
2371 return unicode_lex(c);
2372 }
2373 }
2374
2375 static const VowelComponents Bengali_vowels[] = {
2376 {0x09CB, {0x09C7,0x09BE,0x0000}},
2377 {0x09CC, {0x09C7,0x09D7,0x0000}},
2378 {0x0000, {0x0000,0x0000,0x0000}}};
2379
2380 static const ConsonantComponents Bengali_consonants[] = {
2381 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2382 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2383 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2384 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2385 {{0x0000,0x0000,0x0000}, 0x0000}};
2386
2387 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2388 {
2389 int cCount = cChars;
2390 WCHAR *input;
2391 IndicSyllable *syllables = NULL;
2392 int syllable_count = 0;
2393 BOOL modern = get_GSUB_Indic2(psa, psc);
2394
2395 if (*pcGlyphs != cChars)
2396 {
2397 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2398 return;
2399 }
2400
2401 input = heap_alloc(2 * cChars * sizeof(*input));
2402 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2403
2404 /* Step 1: Decompose Vowels and Compose Consonants */
2405 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2406 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2407 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2408
2409 /* Step 2: Reorder within Syllables */
2410 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2411 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2412 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2413 *pcGlyphs = cCount;
2414
2415 /* Step 3: Initial form is only applied to the beginning of words */
2416 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2417 {
2418 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2419 {
2420 int index = cCount;
2421 int gCount = 1;
2422 if (index > 0) index++;
2423
2424 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2425 }
2426 }
2427
2428 /* Step 4: Base Form application to syllables */
2429 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2430
2431 heap_free(input);
2432 heap_free(syllables);
2433 }
2434
2435 static int gurmukhi_lex(WCHAR c)
2436 {
2437 if (c == 0x0A71)
2438 return lex_Modifier;
2439 else
2440 return unicode_lex(c);
2441 }
2442
2443 static const ConsonantComponents Gurmukhi_consonants[] = {
2444 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2445 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2446 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2447 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2448 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2449 {{0x0000,0x0000,0x0000}, 0x0000}};
2450
2451 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2452 {
2453 int cCount = cChars;
2454 WCHAR *input;
2455 IndicSyllable *syllables = NULL;
2456 int syllable_count = 0;
2457 BOOL modern = get_GSUB_Indic2(psa, psc);
2458
2459 if (*pcGlyphs != cChars)
2460 {
2461 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2462 return;
2463 }
2464
2465 input = heap_alloc(cChars * sizeof(*input));
2466 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2467
2468 /* Step 1: Compose Consonants */
2469 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2470 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2471
2472 /* Step 2: Reorder within Syllables */
2473 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2474 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2475 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2476 *pcGlyphs = cCount;
2477
2478 /* Step 3: Base Form application to syllables */
2479 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2480
2481 heap_free(input);
2482 heap_free(syllables);
2483 }
2484
2485 static int gujarati_lex(WCHAR c)
2486 {
2487 switch (c)
2488 {
2489 case 0x0AB0: return lex_Ra;
2490 default:
2491 return unicode_lex(c);
2492 }
2493 }
2494
2495 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2496 {
2497 int cCount = cChars;
2498 WCHAR *input;
2499 IndicSyllable *syllables = NULL;
2500 int syllable_count = 0;
2501 BOOL modern = get_GSUB_Indic2(psa, psc);
2502
2503 if (*pcGlyphs != cChars)
2504 {
2505 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2506 return;
2507 }
2508
2509 input = heap_alloc(cChars * sizeof(*input));
2510 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2511
2512 /* Step 1: Reorder within Syllables */
2513 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2514 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2515 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2516 *pcGlyphs = cCount;
2517
2518 /* Step 2: Base Form application to syllables */
2519 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2520
2521 heap_free(input);
2522 heap_free(syllables);
2523 }
2524
2525 static int oriya_lex(WCHAR c)
2526 {
2527 switch (c)
2528 {
2529 case 0x0B30: return lex_Ra;
2530 default:
2531 return unicode_lex(c);
2532 }
2533 }
2534
2535 static const VowelComponents Oriya_vowels[] = {
2536 {0x0B48, {0x0B47,0x0B56,0x0000}},
2537 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2538 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2539 {0x0000, {0x0000,0x0000,0x0000}}};
2540
2541 static const ConsonantComponents Oriya_consonants[] = {
2542 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2543 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2544 {{0x0000,0x0000,0x0000}, 0x0000}};
2545
2546 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2547 {
2548 int cCount = cChars;
2549 WCHAR *input;
2550 IndicSyllable *syllables = NULL;
2551 int syllable_count = 0;
2552 BOOL modern = get_GSUB_Indic2(psa, psc);
2553
2554 if (*pcGlyphs != cChars)
2555 {
2556 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2557 return;
2558 }
2559
2560 input = heap_alloc(2 * cChars * sizeof(*input));
2561 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2562
2563 /* Step 1: Decompose Vowels and Compose Consonants */
2564 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2565 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2566 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2567
2568 /* Step 2: Reorder within Syllables */
2569 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2570 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2571 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2572 *pcGlyphs = cCount;
2573
2574 /* Step 3: Base Form application to syllables */
2575 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2576
2577 heap_free(input);
2578 heap_free(syllables);
2579 }
2580
2581 static int tamil_lex(WCHAR c)
2582 {
2583 return unicode_lex(c);
2584 }
2585
2586 static const VowelComponents Tamil_vowels[] = {
2587 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2588 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2589 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2590 {0x0000, {0x0000,0x0000,0x0000}}};
2591
2592 static const ConsonantComponents Tamil_consonants[] = {
2593 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2594 {{0x0000,0x0000,0x0000}, 0x0000}};
2595
2596 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2597 {
2598 int cCount = cChars;
2599 WCHAR *input;
2600 IndicSyllable *syllables = NULL;
2601 int syllable_count = 0;
2602 BOOL modern = get_GSUB_Indic2(psa, psc);
2603
2604 if (*pcGlyphs != cChars)
2605 {
2606 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2607 return;
2608 }
2609
2610 input = heap_alloc(2 * cChars * sizeof(*input));
2611 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2612
2613 /* Step 1: Decompose Vowels and Compose Consonants */
2614 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2615 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2616 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2617
2618 /* Step 2: Reorder within Syllables */
2619 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2620 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2621 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2622 *pcGlyphs = cCount;
2623
2624 /* Step 3: Base Form application to syllables */
2625 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2626
2627 heap_free(input);
2628 heap_free(syllables);
2629 }
2630
2631 static int telugu_lex(WCHAR c)
2632 {
2633 switch (c)
2634 {
2635 case 0x0C43:
2636 case 0x0C44: return lex_Modifier;
2637 default:
2638 return unicode_lex(c);
2639 }
2640 }
2641
2642 static const VowelComponents Telugu_vowels[] = {
2643 {0x0C48, {0x0C46,0x0C56,0x0000}},
2644 {0x0000, {0x0000,0x0000,0x0000}}};
2645
2646 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2647 {
2648 int cCount = cChars;
2649 WCHAR *input;
2650 IndicSyllable *syllables = NULL;
2651 int syllable_count = 0;
2652 BOOL modern = get_GSUB_Indic2(psa, psc);
2653
2654 if (*pcGlyphs != cChars)
2655 {
2656 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2657 return;
2658 }
2659
2660 input = heap_alloc(2 * cChars * sizeof(*input));
2661 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2662
2663 /* Step 1: Decompose Vowels */
2664 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2665 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2666
2667 /* Step 2: Reorder within Syllables */
2668 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2669 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2670 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2671 *pcGlyphs = cCount;
2672
2673 /* Step 3: Base Form application to syllables */
2674 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2675
2676 heap_free(input);
2677 heap_free(syllables);
2678 }
2679
2680 static int kannada_lex(WCHAR c)
2681 {
2682 switch (c)
2683 {
2684 case 0x0CB0: return lex_Ra;
2685 default:
2686 return unicode_lex(c);
2687 }
2688 }
2689
2690 static const VowelComponents Kannada_vowels[] = {
2691 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2692 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2693 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2694 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2695 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2696 {0x0000, {0x0000,0x0000,0x0000}}};
2697
2698 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2699 {
2700 int cCount = cChars;
2701 WCHAR *input;
2702 IndicSyllable *syllables = NULL;
2703 int syllable_count = 0;
2704 BOOL modern = get_GSUB_Indic2(psa, psc);
2705
2706 if (*pcGlyphs != cChars)
2707 {
2708 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2709 return;
2710 }
2711
2712 input = heap_alloc(3 * cChars * sizeof(*input));
2713 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2714
2715 /* Step 1: Decompose Vowels */
2716 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2717 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2718
2719 /* Step 2: Reorder within Syllables */
2720 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2721 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2722 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2723 *pcGlyphs = cCount;
2724
2725 /* Step 3: Base Form application to syllables */
2726 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2727
2728 heap_free(input);
2729 heap_free(syllables);
2730 }
2731
2732 static int malayalam_lex(WCHAR c)
2733 {
2734 return unicode_lex(c);
2735 }
2736
2737 static const VowelComponents Malayalam_vowels[] = {
2738 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2739 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2740 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2741 {0x0000, {0x0000,0x0000,0x0000}}};
2742
2743 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2744 {
2745 int cCount = cChars;
2746 WCHAR *input;
2747 IndicSyllable *syllables = NULL;
2748 int syllable_count = 0;
2749 BOOL modern = get_GSUB_Indic2(psa, psc);
2750
2751 if (*pcGlyphs != cChars)
2752 {
2753 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2754 return;
2755 }
2756
2757 input = heap_alloc(2 * cChars * sizeof(*input));
2758 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2759
2760 /* Step 1: Decompose Vowels */
2761 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2762 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2763
2764 /* Step 2: Reorder within Syllables */
2765 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2766 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2767 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2768 *pcGlyphs = cCount;
2769
2770 /* Step 3: Base Form application to syllables */
2771 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2772
2773 heap_free(input);
2774 heap_free(syllables);
2775 }
2776
2777 static int khmer_lex(WCHAR c)
2778 {
2779 return unicode_lex(c);
2780 }
2781
2782 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2783 {
2784 int cCount = cChars;
2785 WCHAR *input;
2786 IndicSyllable *syllables = NULL;
2787 int syllable_count = 0;
2788
2789 if (*pcGlyphs != cChars)
2790 {
2791 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2792 return;
2793 }
2794
2795 input = heap_alloc(cChars * sizeof(*input));
2796 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2797
2798 /* Step 1: Reorder within Syllables */
2799 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2800 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2801 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2802 *pcGlyphs = cCount;
2803
2804 /* Step 2: Base Form application to syllables */
2805 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2806
2807 heap_free(input);
2808 heap_free(syllables);
2809 }
2810
2811 static inline BOOL mongolian_wordbreak(WCHAR chr)
2812 {
2813 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2814 }
2815
2816 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2817 {
2818 INT *context_shape;
2819 INT dirL;
2820 int i;
2821 int char_index;
2822 int glyph_index;
2823
2824 if (*pcGlyphs != cChars)
2825 {
2826 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2827 return;
2828 }
2829
2830 if (!psa->fLogicalOrder && psa->fRTL)
2831 dirL = -1;
2832 else
2833 dirL = 1;
2834
2835 if (!psc->GSUB_Table)
2836 return;
2837
2838 context_shape = heap_alloc(cChars * sizeof(*context_shape));
2839
2840 for (i = 0; i < cChars; i++)
2841 {
2842 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2843 {
2844 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2845 context_shape[i] = Xn;
2846 else
2847 context_shape[i] = Xl;
2848 }
2849 else
2850 {
2851 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2852 context_shape[i] = Xr;
2853 else
2854 context_shape[i] = Xm;
2855 }
2856 }
2857
2858 /* Contextual Shaping */
2859 if (dirL > 0)
2860 char_index = glyph_index = 0;
2861 else
2862 char_index = glyph_index = cChars-1;
2863
2864 while(char_index < cChars && char_index >= 0)
2865 {
2866 INT nextIndex;
2867 INT prevCount = *pcGlyphs;
2868 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2869
2870 if (nextIndex > GSUB_E_NOGLYPH)
2871 {
2872 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2873 glyph_index = nextIndex;
2874 char_index += dirL;
2875 }
2876 else
2877 {
2878 char_index += dirL;
2879 glyph_index += dirL;
2880 }
2881 }
2882
2883 heap_free(context_shape);
2884 }
2885
2886 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
2887 {
2888 int i,k;
2889
2890 for (i = 0; i < cGlyphs; i++)
2891 {
2892 int char_index[20];
2893 int char_count = 0;
2894
2895 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2896 if (k>=0)
2897 {
2898 for (; k < cChars && pwLogClust[k] == i; k++)
2899 char_index[char_count++] = k;
2900 }
2901
2902 if (char_count == 0)
2903 continue;
2904
2905 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2906 {
2907 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2908 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2909 }
2910 else
2911 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2912 }
2913
2914 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2915 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2916 }
2917
2918 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2919 {
2920 int i;
2921
2922 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2923
2924 for (i = 0; i < cGlyphs; i++)
2925 if (pGlyphProp[i].sva.fZeroWidth)
2926 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2927 }
2928
2929 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2930 {
2931 int i;
2932 for (i = 0; i < cGlyphs; i++)
2933 {
2934 pGlyphProp[i].sva.fClusterStart = 1;
2935 pGlyphProp[i].sva.fDiacritic = 0;
2936 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2937
2938 if (pwGlyphs[i] == psc->sfp.wgDefault)
2939 pGlyphProp[i].sva.fZeroWidth = 0;
2940 else
2941 pGlyphProp[i].sva.fZeroWidth = 1;
2942 }
2943 }
2944
2945 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2946 {
2947 int i,k;
2948 int initGlyph, finaGlyph;
2949 INT dirR, dirL;
2950 BYTE *spaces;
2951
2952 spaces = heap_alloc(cGlyphs);
2953 memset(spaces,0,cGlyphs);
2954
2955 if (psa->fLogicalOrder && psa->fRTL)
2956 {
2957 initGlyph = 0;
2958 finaGlyph = cGlyphs-1;
2959 dirR = -1;
2960 dirL = 1;
2961 }
2962 else
2963 {
2964 initGlyph = cGlyphs-1;
2965 finaGlyph = 0;
2966 dirR = 1;
2967 dirL = -1;
2968 }
2969
2970 for (i = 0; i < cGlyphs; i++)
2971 {
2972 for (k = 0; k < cChars; k++)
2973 if (pwLogClust[k] == i)
2974 {
2975 if (pwcChars[k] == 0x0020)
2976 spaces[i] = 1;
2977 }
2978 }
2979
2980 for (i = 0; i < cGlyphs; i++)
2981 {
2982 int char_index[20];
2983 int char_count = 0;
2984 BOOL isInit, isFinal;
2985
2986 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2987 if (k>=0)
2988 {
2989 for (; k < cChars && pwLogClust[k] == i; k++)
2990 char_index[char_count++] = k;
2991 }
2992
2993 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2994 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2995
2996 if (char_count == 0)
2997 continue;
2998
2999 if (char_count == 1)
3000 {
3001 if (pwcChars[char_index[0]] == 0x0020) /* space */
3002 {
3003 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3004 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3005 }
3006 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3007 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3008 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3009 {
3010 if (!isInit && !isFinal)
3011 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3012 else if (isInit)
3013 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3014 else
3015 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3016 }
3017 else if (!isInit)
3018 {
3019 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3020 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3021 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3022 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3023 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3024 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3025 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3026 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3027 else
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3029 }
3030 else if (!isInit && !isFinal)
3031 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3032 else
3033 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3034 }
3035 else if (char_count == 2)
3036 {
3037 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3038 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3039 else if (!isInit)
3040 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3041 else
3042 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3043 }
3044 else if (!isInit && !isFinal)
3045 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3046 else
3047 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3048 }
3049
3050 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3051 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3052 heap_free(spaces);
3053 }
3054
3055 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3056 {
3057 int i,k;
3058
3059 for (i = 0; i < cGlyphs; i++)
3060 {
3061 int char_index[20];
3062 int char_count = 0;
3063
3064 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3065 if (k>=0)
3066 {
3067 for (; k < cChars && pwLogClust[k] == i; k++)
3068 char_index[char_count++] = k;
3069 }
3070
3071 if (char_count == 0)
3072 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3073 else
3074 {
3075 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3076 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3077 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3078 }
3079 }
3080
3081 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3082 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3083 }
3084
3085 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3086 {
3087 int i;
3088 int finaGlyph;
3089 INT dirL;
3090
3091 if (!psa->fLogicalOrder && psa->fRTL)
3092 {
3093 finaGlyph = 0;
3094 dirL = -1;
3095 }
3096 else
3097 {
3098 finaGlyph = cGlyphs-1;
3099 dirL = 1;
3100 }
3101
3102 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3103
3104 for (i = 0; i < cGlyphs; i++)
3105 {
3106 int k;
3107 int char_index[20];
3108 int char_count = 0;
3109
3110 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3111 if (k>=0)
3112 {
3113 for (; k < cChars && pwLogClust[k] == i; k++)
3114 char_index[char_count++] = k;
3115 }
3116
3117 if (i == finaGlyph)
3118 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3119 else
3120 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3121
3122 if (char_count == 0)
3123 continue;
3124
3125 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3126 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3127
3128 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3129 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3130 pGlyphProp[i].sva.fClusterStart = 0;
3131 }
3132
3133 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3134
3135 /* Do not allow justification between marks and their base */
3136 for (i = 0; i < cGlyphs; i++)
3137 {
3138 if (!pGlyphProp[i].sva.fClusterStart)
3139 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3140 }
3141 }
3142
3143 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
3144 {
3145 int i,k;
3146
3147 for (i = 0; i < cGlyphs; i++)
3148 {
3149 int char_index[20];
3150 int char_count = 0;
3151
3152 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3153 if (k>=0)
3154 {
3155 for (; k < cChars && pwLogClust[k] == i; k++)
3156 char_index[char_count++] = k;
3157 }
3158
3159 if (char_count == 0)
3160 continue;
3161
3162 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3163 {
3164 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3165 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3166 }
3167 else
3168 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3169 }
3170 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3171 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3172 }
3173
3174 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
3175 {
3176 int i,k;
3177
3178 for (i = 0; i < cGlyphs; i++)
3179 {
3180 int char_index[20];
3181 int char_count = 0;
3182
3183 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3184 if (k>=0)
3185 {
3186 for (; k < cChars && pwLogClust[k] == i; k++)
3187 char_index[char_count++] = k;
3188 }
3189
3190 if (char_count == 0)
3191 continue;
3192
3193 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3194 {
3195 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3196 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3197 }
3198 else
3199 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3200 }
3201 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3202 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3203
3204 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3205 for (i = 0; i < cGlyphs; i++)
3206 {
3207 if (!pGlyphProp[i].sva.fClusterStart)
3208 {
3209 pGlyphProp[i].sva.fDiacritic = 0;
3210 pGlyphProp[i].sva.fZeroWidth = 0;
3211 }
3212 }
3213 }
3214
3215 static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables, BOOL override_gsub)
3216 {
3217 int i,k;
3218
3219 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3220 for (i = 0; i < cGlyphs; i++)
3221 {
3222 int char_index[20];
3223 int char_count = 0;
3224
3225 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3226 if (k>=0)
3227 {
3228 for (; k < cChars && pwLogClust[k] == i; k++)
3229 char_index[char_count++] = k;
3230 }
3231
3232 if (override_gsub)
3233 {
3234 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3235 pGlyphProp[i].sva.fDiacritic = FALSE;
3236 pGlyphProp[i].sva.fZeroWidth = FALSE;
3237 }
3238
3239 if (char_count == 0)
3240 {
3241 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3242 continue;
3243 }
3244
3245 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3246 {
3247 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3248 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3249 }
3250 else
3251 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3252
3253 pGlyphProp[i].sva.fClusterStart = 0;
3254 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3255 switch (lexical(pwcChars[char_index[k]]))
3256 {
3257 case lex_Matra_pre:
3258 case lex_Matra_post:
3259 case lex_Matra_above:
3260 case lex_Matra_below:
3261 case lex_Modifier:
3262 case lex_Halant:
3263 break;
3264 case lex_ZWJ:
3265 case lex_ZWNJ:
3266 /* check for dangling joiners */
3267 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3268 pGlyphProp[i].sva.fClusterStart = 1;
3269 else
3270 k = char_count;
3271 break;
3272 default:
3273 pGlyphProp[i].sva.fClusterStart = 1;
3274 break;
3275 }
3276 }
3277
3278 if (use_syllables)
3279 {
3280 IndicSyllable *syllables = NULL;
3281 int syllable_count = 0;
3282 BOOL modern = get_GSUB_Indic2(psa, psc);
3283
3284 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3285
3286 for (i = 0; i < syllable_count; i++)
3287 {
3288 int j;
3289 WORD g = pwLogClust[syllables[i].start];
3290 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3291 {
3292 if (pwLogClust[j] != g)
3293 {
3294 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3295 pwLogClust[j] = g;
3296 }
3297 }
3298 }
3299
3300 heap_free(syllables);
3301 }
3302
3303 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3304 }
3305
3306 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3307 {
3308 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3309 }
3310
3311 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3312 {
3313 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3314 }
3315
3316 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3317 {
3318 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3319 }
3320
3321 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3322 {
3323 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3324 }
3325
3326 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3327 {
3328 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3329 }
3330
3331 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3332 {
3333 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3334 }
3335
3336 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3337 {
3338 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3339 }
3340
3341 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3342 {
3343 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3344 }
3345
3346 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3347 {
3348 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3349 }
3350
3351 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3352 {
3353 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3354 }
3355
3356 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3357 {
3358 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3359 }
3360
3361 void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp)
3362 {
3363 load_ot_tables(hdc, psc);
3364
3365 if (ShapingData[psa->eScript].charGlyphPropProc)
3366 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3367 else
3368 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3369 }
3370
3371 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3372 {
3373 load_ot_tables(hdc, psc);
3374
3375 if (ShapingData[psa->eScript].contextProc)
3376 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3377 }
3378
3379 static void SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, const TEXTRANGE_PROPERTIES *rpRangeProperties, WORD *pwLogClust)
3380 {
3381 int i;
3382 INT dirL;
3383
3384 if (!rpRangeProperties)
3385 return;
3386
3387 load_ot_tables(hdc, psc);
3388
3389 if (!psc->GSUB_Table)
3390 return;
3391
3392 if (scriptInformation[psa->eScript].a.fRTL && (!psa->fLogicalOrder || !psa->fRTL))
3393 dirL = -1;
3394 else
3395 dirL = 1;
3396
3397 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3398 {
3399 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3400 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3401 }
3402 }
3403
3404 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3405 {
3406 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3407 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3408
3409 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3410 }
3411
3412 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3413 {
3414 const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3415 int i;
3416
3417 load_ot_tables(hdc, psc);
3418
3419 if (!psc->GPOS_Table || !psc->otm)
3420 return;
3421
3422 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3423 {
3424 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3425 {
3426 LoadedFeature *feature;
3427
3428 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3429 if (!feature)
3430 continue;
3431
3432 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3433 }
3434 }
3435 }
3436
3437 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3438 {
3439 LoadedFeature *feature;
3440 int i;
3441
3442 if (!ShapingData[psa->eScript].requiredFeatures)
3443 return S_OK;
3444
3445 load_ot_tables(hdc, psc);
3446
3447 /* we need to have at least one of the required features */
3448 i = 0;
3449 while (ShapingData[psa->eScript].requiredFeatures[i])
3450 {
3451 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3452 if (feature)
3453 return S_OK;
3454 i++;
3455 }
3456
3457 return USP_E_SCRIPT_NOT_IN_FONT;
3458 }
3459
3460 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3461 SCRIPT_ANALYSIS *psa, int cMaxTags,
3462 OPENTYPE_TAG *pScriptTags, int *pcTags)
3463 {
3464 HRESULT hr;
3465 OPENTYPE_TAG searching = 0x00000000;
3466
3467 load_ot_tables(hdc, psc);
3468
3469 if (psa && scriptInformation[psa->eScript].scriptTag)
3470 searching = scriptInformation[psa->eScript].scriptTag;
3471
3472 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3473 if (FAILED(hr))
3474 *pcTags = 0;
3475 return hr;
3476 }
3477
3478 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3479 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3480 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3481 int *pcTags)
3482 {
3483 HRESULT hr;
3484 OPENTYPE_TAG searching = 0x00000000;
3485 BOOL fellback = FALSE;
3486
3487 load_ot_tables(hdc, psc);
3488
3489 if (psa && psc->userLang != 0)
3490 searching = psc->userLang;
3491
3492 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3493 if (FAILED(hr))
3494 {
3495 fellback = TRUE;
3496 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3497 }
3498
3499 if (FAILED(hr) || fellback)
3500 *pcTags = 0;
3501 if (SUCCEEDED(hr) && fellback && psa)
3502 hr = E_INVALIDARG;
3503 return hr;
3504 }
3505
3506 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3507 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3508 OPENTYPE_TAG tagLangSys, int cMaxTags,
3509 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3510 {
3511 HRESULT hr;
3512 BOOL filter = FALSE;
3513
3514 load_ot_tables(hdc, psc);
3515
3516 if (psa && scriptInformation[psa->eScript].scriptTag)
3517 {
3518 FIXME("Filtering not implemented\n");
3519 filter = TRUE;
3520 }
3521
3522 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3523
3524 if (FAILED(hr))
3525 *pcTags = 0;
3526 return hr;
3527 }