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