[USP10] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / reactos / dll / win32 / usp10 / shape.c
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
3 *
4 * Copyright 2010 CodeWeavers, Aric Stewart
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 */
21
22 #include "usp10_internal.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
25
26 #define FIRST_ARABIC_CHAR 0x0600
27 #define LAST_ARABIC_CHAR 0x06ff
28
29 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
30 WCHAR*, INT, WORD*, INT*, INT, WORD*);
31
32 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
33 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
34 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
35 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
36 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
37 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
38 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
39 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
40 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
41 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
42 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
43 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52
53 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
54
55 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
56 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
57 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
58 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
59 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
60 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
61 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
62 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
63 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
64 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
65 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
66 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
67 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
68 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
73 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74
75 extern const unsigned short indic_syllabic_table[];
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 0x000A:
942 case 0x000D:
943 pwOutGlyphs[i] = psc->sfp.wgBlank;
944 break;
945 default:
946 if (pwcChars[i] < 0x1C)
947 pwOutGlyphs[i] = psc->sfp.wgDefault;
948 else
949 pwOutGlyphs[i] = psc->sfp.wgBlank;
950 }
951 }
952 }
953
954 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
955 {
956 if (i + delta < 0)
957 return 0;
958 if ( i+ delta >= cchLen)
959 return 0;
960
961 i += delta;
962
963 return chars[i];
964 }
965
966 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
967 {
968 if (i + delta < 0)
969 {
970 if (psa->fLinkBefore)
971 return jtR;
972 else
973 return jtU;
974 }
975 if ( i+ delta >= cchLen)
976 {
977 if (psa->fLinkAfter)
978 return jtL;
979 else
980 return jtU;
981 }
982
983 i += delta;
984
985 if (context_type[i] == jtT)
986 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
987 else
988 return context_type[i];
989 }
990
991 static inline BOOL right_join_causing(CHAR joining_type)
992 {
993 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
994 }
995
996 static inline BOOL left_join_causing(CHAR joining_type)
997 {
998 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
999 }
1000
1001 static inline BOOL word_break_causing(WCHAR chr)
1002 {
1003 /* we are working within a string of characters already guareented to
1004 be within one script, Syriac, so we do not worry about any character
1005 other than the space character outside of that range */
1006 return (chr == 0 || chr == 0x20 );
1007 }
1008
1009 static int combining_lexical_Arabic(WCHAR c)
1010 {
1011 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1012
1013 switch(c)
1014 {
1015 case 0x064B:
1016 case 0x064C:
1017 case 0x064E:
1018 case 0x064F:
1019 case 0x0652:
1020 case 0x0657:
1021 case 0x0658:
1022 case 0x06E1: return Arab_DIAC1;
1023 case 0x064D:
1024 case 0x0650:
1025 case 0x0656: return Arab_DIAC2;
1026 case 0x0651: return Arab_DIAC3;
1027 case 0x0610:
1028 case 0x0611:
1029 case 0x0612:
1030 case 0x0613:
1031 case 0x0614:
1032 case 0x0659:
1033 case 0x06D6:
1034 case 0x06DC:
1035 case 0x06DF:
1036 case 0x06E0:
1037 case 0x06E2:
1038 case 0x06E4:
1039 case 0x06E7:
1040 case 0x06E8:
1041 case 0x06EB:
1042 case 0x06EC: return Arab_DIAC4;
1043 case 0x06E3:
1044 case 0x06EA:
1045 case 0x06ED: return Arab_DIAC5;
1046 case 0x0670: return Arab_DIAC6;
1047 case 0x0653: return Arab_DIAC7;
1048 case 0x0655:
1049 case 0x0654: return Arab_DIAC8;
1050 default: return Arab_Norm;
1051 }
1052 }
1053
1054 /*
1055 * ContextualShape_Arabic
1056 */
1057 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1058 {
1059 CHAR *context_type;
1060 INT *context_shape;
1061 INT dirR, dirL;
1062 int i;
1063
1064 if (*pcGlyphs != cChars)
1065 {
1066 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1067 return;
1068 }
1069
1070 if (!psa->fLogicalOrder && psa->fRTL)
1071 {
1072 dirR = 1;
1073 dirL = -1;
1074 }
1075 else
1076 {
1077 dirR = -1;
1078 dirL = 1;
1079 }
1080
1081 load_ot_tables(hdc, psc);
1082
1083 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1084 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1085
1086 for (i = 0; i < cChars; i++)
1087 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1088
1089 for (i = 0; i < cChars; i++)
1090 {
1091 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1092 context_shape[i] = Xr;
1093 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1094 context_shape[i] = Xl;
1095 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)))
1096 context_shape[i] = Xm;
1097 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1098 context_shape[i] = Xr;
1099 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1100 context_shape[i] = Xl;
1101 else
1102 context_shape[i] = Xn;
1103 }
1104
1105 /* Contextual Shaping */
1106 i = 0;
1107 while(i < *pcGlyphs)
1108 {
1109 BOOL shaped = FALSE;
1110
1111 if (psc->GSUB_Table)
1112 {
1113 INT nextIndex;
1114 INT prevCount = *pcGlyphs;
1115 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1116 if (nextIndex > GSUB_E_NOGLYPH)
1117 {
1118 i = nextIndex;
1119 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1120 }
1121 shaped = (nextIndex > GSUB_E_NOGLYPH);
1122 }
1123
1124 if (!shaped)
1125 {
1126 if (context_shape[i] == Xn)
1127 {
1128 WORD newGlyph = pwOutGlyphs[i];
1129 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1130 {
1131 /* fall back to presentation form B */
1132 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1133 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1134 pwOutGlyphs[i] = newGlyph;
1135 }
1136 }
1137 i++;
1138 }
1139 }
1140
1141 HeapFree(GetProcessHeap(),0,context_shape);
1142 HeapFree(GetProcessHeap(),0,context_type);
1143
1144 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1145 }
1146
1147 static int combining_lexical_Hebrew(WCHAR c)
1148 {
1149 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};
1150
1151 switch(c)
1152 {
1153 case 0x05B0:
1154 case 0x05B1:
1155 case 0x05B2:
1156 case 0x05B3:
1157 case 0x05B4:
1158 case 0x05B5:
1159 case 0x05B6:
1160 case 0x05BB: return Hebr_DIAC;
1161 case 0x0599:
1162 case 0x05A1:
1163 case 0x05A9:
1164 case 0x05AE: return Hebr_CANT1;
1165 case 0x0597:
1166 case 0x05A8:
1167 case 0x05AC: return Hebr_CANT2;
1168 case 0x0592:
1169 case 0x0593:
1170 case 0x0594:
1171 case 0x0595:
1172 case 0x05A7:
1173 case 0x05AB: return Hebr_CANT3;
1174 case 0x0598:
1175 case 0x059C:
1176 case 0x059E:
1177 case 0x059F: return Hebr_CANT4;
1178 case 0x059D:
1179 case 0x05A0: return Hebr_CANT5;
1180 case 0x059B:
1181 case 0x05A5: return Hebr_CANT6;
1182 case 0x0591:
1183 case 0x05A3:
1184 case 0x05A6: return Hebr_CANT7;
1185 case 0x0596:
1186 case 0x05A4:
1187 case 0x05AA: return Hebr_CANT8;
1188 case 0x059A:
1189 case 0x05AD: return Hebr_CANT9;
1190 case 0x05AF: return Hebr_CANT10;
1191 case 0x05BC: return Hebr_DAGESH;
1192 case 0x05C4: return Hebr_DOTABV;
1193 case 0x05B9: return Hebr_HOLAM;
1194 case 0x05BD: return Hebr_METEG;
1195 case 0x05B7: return Hebr_PATAH;
1196 case 0x05B8: return Hebr_QAMATS;
1197 case 0x05BF: return Hebr_RAFE;
1198 case 0x05C1:
1199 case 0x05C2: return Hebr_SHINSIN;
1200 default: return Hebr_Norm;
1201 }
1202 }
1203
1204 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1205 {
1206 INT dirL;
1207
1208 if (*pcGlyphs != cChars)
1209 {
1210 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1211 return;
1212 }
1213
1214 if (!psa->fLogicalOrder && psa->fRTL)
1215 dirL = -1;
1216 else
1217 dirL = 1;
1218
1219 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1220 }
1221
1222 /*
1223 * ContextualShape_Syriac
1224 */
1225
1226 static int combining_lexical_Syriac(WCHAR c)
1227 {
1228 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};
1229
1230 switch(c)
1231 {
1232 case 0x730:
1233 case 0x733:
1234 case 0x736:
1235 case 0x73A:
1236 case 0x73D: return Syriac_DIAC1;
1237 case 0x731:
1238 case 0x734:
1239 case 0x737:
1240 case 0x73B:
1241 case 0x73E: return Syriac_DIAC2;
1242 case 0x740:
1243 case 0x749:
1244 case 0x74A: return Syriac_DIAC3;
1245 case 0x732:
1246 case 0x735:
1247 case 0x73F: return Syriac_DIAC4;
1248 case 0x738:
1249 case 0x739:
1250 case 0x73C: return Syriac_DIAC5;
1251 case 0x741:
1252 case 0x30A: return Syriac_DIAC6;
1253 case 0x742:
1254 case 0x325: return Syriac_DIAC7;
1255 case 0x747:
1256 case 0x303: return Syriac_DIAC8;
1257 case 0x748:
1258 case 0x32D:
1259 case 0x32E:
1260 case 0x330:
1261 case 0x331: return Syriac_DIAC9;
1262 case 0x308: return Syriac_DIAC10;
1263 case 0x304: return Syriac_DIAC11;
1264 case 0x307: return Syriac_DIAC12;
1265 case 0x323: return Syriac_DIAC13;
1266 case 0x743: return Syriac_DIAC14;
1267 case 0x744: return Syriac_DIAC15;
1268 case 0x745: return Syriac_DIAC16;
1269 case 0x746: return Syriac_DIAC17;
1270 default: return Syriac_Norm;
1271 }
1272 }
1273
1274 #define ALAPH 0x710
1275 #define DALATH 0x715
1276 #define RISH 0x72A
1277
1278 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1279 {
1280 CHAR *context_type;
1281 INT *context_shape;
1282 INT dirR, dirL;
1283 int i;
1284
1285 if (*pcGlyphs != cChars)
1286 {
1287 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1288 return;
1289 }
1290
1291 if (!psa->fLogicalOrder && psa->fRTL)
1292 {
1293 dirR = 1;
1294 dirL = -1;
1295 }
1296 else
1297 {
1298 dirR = -1;
1299 dirL = 1;
1300 }
1301
1302 load_ot_tables(hdc, psc);
1303
1304 if (!psc->GSUB_Table)
1305 return;
1306
1307 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1308 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1309
1310 for (i = 0; i < cChars; i++)
1311 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1312
1313 for (i = 0; i < cChars; i++)
1314 {
1315 if (pwcChars[i] == ALAPH)
1316 {
1317 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1318
1319 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1320 context_shape[i] = Afj;
1321 else if ( rchar != DALATH && rchar != RISH &&
1322 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1323 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1324 context_shape[i] = Afn;
1325 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1326 context_shape[i] = Afx;
1327 else
1328 context_shape[i] = Xn;
1329 }
1330 else if (context_type[i] == jtR &&
1331 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1332 context_shape[i] = Xr;
1333 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1334 context_shape[i] = Xl;
1335 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)))
1336 context_shape[i] = Xm;
1337 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1338 context_shape[i] = Xr;
1339 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1340 context_shape[i] = Xl;
1341 else
1342 context_shape[i] = Xn;
1343 }
1344
1345 /* Contextual Shaping */
1346 i = 0;
1347 while(i < *pcGlyphs)
1348 {
1349 INT nextIndex;
1350 INT prevCount = *pcGlyphs;
1351 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1352 if (nextIndex > GSUB_E_NOGLYPH)
1353 {
1354 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1355 i = nextIndex;
1356 }
1357 else
1358 i++;
1359 }
1360
1361 HeapFree(GetProcessHeap(),0,context_shape);
1362 HeapFree(GetProcessHeap(),0,context_type);
1363
1364 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1365 }
1366
1367 static int combining_lexical_Thaana(WCHAR c)
1368 {
1369 enum {Thaana_Norm=0, Thaana_FILI};
1370
1371 switch(c)
1372 {
1373 case 0x7A6:
1374 case 0x7A7:
1375 case 0x7A8:
1376 case 0x7A9:
1377 case 0x7AA:
1378 case 0x7AB:
1379 case 0x7AC:
1380 case 0x7AD:
1381 case 0x7AE:
1382 case 0x7AF: return Thaana_FILI;
1383 default: return Thaana_Norm;
1384 }
1385 }
1386
1387 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1388 {
1389 INT dirL;
1390
1391 if (*pcGlyphs != cChars)
1392 {
1393 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1394 return;
1395 }
1396
1397 if (!psa->fLogicalOrder && psa->fRTL)
1398 dirL = -1;
1399 else
1400 dirL = 1;
1401
1402 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1403 }
1404
1405 /*
1406 * ContextualShape_Phags_pa
1407 */
1408
1409 #define phags_pa_CANDRABINDU 0xA873
1410 #define phags_pa_START 0xA840
1411 #define phags_pa_END 0xA87F
1412
1413 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1414 {
1415 INT *context_shape;
1416 INT dirR, dirL;
1417 int i;
1418
1419 if (*pcGlyphs != cChars)
1420 {
1421 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1422 return;
1423 }
1424
1425 if (!psa->fLogicalOrder && psa->fRTL)
1426 {
1427 dirR = 1;
1428 dirL = -1;
1429 }
1430 else
1431 {
1432 dirR = -1;
1433 dirL = 1;
1434 }
1435
1436 load_ot_tables(hdc, psc);
1437
1438 if (!psc->GSUB_Table)
1439 return;
1440
1441 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1442
1443 for (i = 0; i < cChars; i++)
1444 {
1445 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1446 {
1447 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1448 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1449 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1450 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1451
1452 if (jrchar && jlchar)
1453 context_shape[i] = Xm;
1454 else if (jrchar)
1455 context_shape[i] = Xr;
1456 else if (jlchar)
1457 context_shape[i] = Xl;
1458 else
1459 context_shape[i] = Xn;
1460 }
1461 else
1462 context_shape[i] = -1;
1463 }
1464
1465 /* Contextual Shaping */
1466 i = 0;
1467 while(i < *pcGlyphs)
1468 {
1469 if (context_shape[i] >= 0)
1470 {
1471 INT nextIndex;
1472 INT prevCount = *pcGlyphs;
1473 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1474 if (nextIndex > GSUB_E_NOGLYPH)
1475 {
1476 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1477 i = nextIndex;
1478 }
1479 else
1480 i++;
1481 }
1482 else
1483 i++;
1484 }
1485
1486 HeapFree(GetProcessHeap(),0,context_shape);
1487 }
1488
1489 static int combining_lexical_Thai(WCHAR c)
1490 {
1491 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1492
1493 switch(c)
1494 {
1495 case 0xE31:
1496 case 0xE34:
1497 case 0xE35:
1498 case 0xE36:
1499 case 0xE37: return Thai_ABOVE1;
1500 case 0xE47:
1501 case 0xE4D: return Thai_ABOVE2;
1502 case 0xE48:
1503 case 0xE49:
1504 case 0xE4A:
1505 case 0xE4B: return Thai_ABOVE3;
1506 case 0xE4C:
1507 case 0xE4E: return Thai_ABOVE4;
1508 case 0xE38:
1509 case 0xE39: return Thai_BELOW1;
1510 case 0xE3A: return Thai_BELOW2;
1511 case 0xE33: return Thai_AM;
1512 default: return Thai_Norm;
1513 }
1514 }
1515
1516 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1517 {
1518 INT dirL;
1519
1520 if (*pcGlyphs != cChars)
1521 {
1522 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1523 return;
1524 }
1525
1526 if (!psa->fLogicalOrder && psa->fRTL)
1527 dirL = -1;
1528 else
1529 dirL = 1;
1530
1531 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1532 }
1533
1534 static int combining_lexical_Lao(WCHAR c)
1535 {
1536 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1537
1538 switch(c)
1539 {
1540 case 0xEB1:
1541 case 0xEB4:
1542 case 0xEB5:
1543 case 0xEB6:
1544 case 0xEB7:
1545 case 0xEBB:
1546 case 0xECD: return Lao_ABOVE1;
1547 case 0xEC8:
1548 case 0xEC9:
1549 case 0xECA:
1550 case 0xECB:
1551 case 0xECC: return Lao_ABOVE2;
1552 case 0xEBC: return Lao_BELOW1;
1553 case 0xEB8:
1554 case 0xEB9: return Lao_BELOW2;
1555 case 0xEB3: return Lao_AM;
1556 default: return Lao_Norm;
1557 }
1558 }
1559
1560 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1561 {
1562 INT dirL;
1563
1564 if (*pcGlyphs != cChars)
1565 {
1566 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1567 return;
1568 }
1569
1570 if (!psa->fLogicalOrder && psa->fRTL)
1571 dirL = -1;
1572 else
1573 dirL = 1;
1574
1575 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1576 }
1577
1578 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1579 {
1580 int i;
1581
1582 /* Replace */
1583 pwOutChars[cWalk] = replacements[0];
1584 cWalk=cWalk+1;
1585
1586 /* Insert */
1587 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1588 {
1589 int j;
1590 for (j = *pcChars; j > cWalk; j--)
1591 pwOutChars[j] = pwOutChars[j-1];
1592 *pcChars= *pcChars+1;
1593 pwOutChars[cWalk] = replacements[i];
1594 cWalk = cWalk+1;
1595 }
1596 }
1597
1598 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1599 {
1600 int i;
1601 int cWalk;
1602
1603 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1604 {
1605 for (i = 0; vowels[i].base != 0x0; i++)
1606 {
1607 if (pwOutChars[cWalk] == vowels[i].base)
1608 {
1609 int o = 0;
1610 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1611 if (vowels[i].parts[1]) { cWalk++; o++; }
1612 if (vowels[i].parts[2]) { cWalk++; o++; }
1613 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1614 break;
1615 }
1616 }
1617 }
1618 }
1619
1620 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1621 {
1622 int i;
1623 int offset = 0;
1624 int cWalk;
1625
1626 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1627 {
1628 for (i = 0; consonants[i].output!= 0x0; i++)
1629 {
1630 int j;
1631 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1632 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1633 break;
1634
1635 if (consonants[i].parts[j]==0x0) /* matched all */
1636 {
1637 int k;
1638 j--;
1639 pwOutChars[cWalk] = consonants[i].output;
1640 for(k = cWalk+1; k < *pcChars - j; k++)
1641 pwOutChars[k] = pwOutChars[k+j];
1642 *pcChars = *pcChars - j;
1643 for (k = j ; k > 0; k--)
1644 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1645 offset += j;
1646 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1647 pwLogClust[k]--;
1648 break;
1649 }
1650 }
1651 cWalk++;
1652 }
1653 }
1654
1655 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1656 {
1657 if (s->ralf >= 0)
1658 {
1659 int j;
1660 WORD Ra = pwChar[s->start];
1661 WORD H = pwChar[s->start+1];
1662
1663 TRACE("Doing reorder of Ra to %i\n",s->base);
1664 for (j = s->start; j < s->base-1; j++)
1665 pwChar[j] = pwChar[j+2];
1666 pwChar[s->base-1] = Ra;
1667 pwChar[s->base] = H;
1668
1669 s->ralf = s->base-1;
1670 s->base -= 2;
1671 }
1672 }
1673
1674 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1675 {
1676 if (s->ralf >= 0)
1677 {
1678 int j,loc;
1679 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1680 WORD Ra = pwChar[s->start];
1681 WORD H = pwChar[s->start+1];
1682 for (loc = s->end; loc > stop; loc--)
1683 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1684 break;
1685
1686 TRACE("Doing reorder of Ra to %i\n",loc);
1687 for (j = s->start; j < loc-1; j++)
1688 pwChar[j] = pwChar[j+2];
1689 pwChar[loc-1] = Ra;
1690 pwChar[loc] = H;
1691
1692 s->ralf = loc-1;
1693 s->base -= 2;
1694 if (s->blwf >= 0) s->blwf -= 2;
1695 if (s->pref >= 0) s->pref -= 2;
1696 }
1697 }
1698
1699 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1700 {
1701 if (s->ralf >= 0)
1702 {
1703 int j;
1704 WORD Ra = pwChar[s->start];
1705 WORD H = pwChar[s->start+1];
1706
1707 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1708 for (j = s->start; j < s->end-1; j++)
1709 pwChar[j] = pwChar[j+2];
1710 pwChar[s->end-1] = Ra;
1711 pwChar[s->end] = H;
1712
1713 s->ralf = s->end-1;
1714 s->base -= 2;
1715 if (s->blwf >= 0) s->blwf -= 2;
1716 if (s->pref >= 0) s->pref -= 2;
1717 }
1718 }
1719
1720 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1721 {
1722 int i;
1723
1724 /* reorder Matras */
1725 if (s->end > s->base)
1726 {
1727 for (i = 1; i <= s->end-s->base; i++)
1728 {
1729 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1730 {
1731 int j;
1732 WCHAR c = pwChar[s->base+i];
1733 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1734 for (j = s->base+i; j > s->base; j--)
1735 pwChar[j] = pwChar[j-1];
1736 pwChar[s->base] = c;
1737
1738 if (s->ralf >= s->base) s->ralf++;
1739 if (s->blwf >= s->base) s->blwf++;
1740 if (s->pref >= s->base) s->pref++;
1741 s->base ++;
1742 }
1743 }
1744 }
1745 }
1746
1747 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1748 {
1749 int i;
1750
1751 /* reorder Matras */
1752 if (s->end > s->base)
1753 {
1754 for (i = 1; i <= s->end-s->base; i++)
1755 {
1756 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1757 {
1758 int j;
1759 WCHAR c = pwChar[s->base+i];
1760 TRACE("Doing reorder of %x to %i\n",c,s->start);
1761 for (j = s->base+i; j > s->start; j--)
1762 pwChar[j] = pwChar[j-1];
1763 pwChar[s->start] = c;
1764
1765 if (s->ralf >= 0) s->ralf++;
1766 if (s->blwf >= 0) s->blwf++;
1767 if (s->pref >= 0) s->pref++;
1768 s->base ++;
1769 }
1770 }
1771 }
1772 }
1773
1774 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1775 {
1776 if (s->blwf >= 0 && g->blwf > g->base)
1777 {
1778 int j,loc;
1779 int g_offset;
1780 for (loc = s->end; loc > s->blwf; loc--)
1781 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1782 break;
1783
1784 g_offset = (loc - s->blwf) - 1;
1785
1786 if (loc != s->blwf)
1787 {
1788 WORD blwf = glyphs[g->blwf];
1789 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1790 /* do not care about the pwChar array anymore, just the glyphs */
1791 for (j = 0; j < g_offset; j++)
1792 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1793 glyphs[g->blwf + g_offset] = blwf;
1794 }
1795 }
1796 }
1797
1798 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1799 {
1800 int i;
1801
1802 /* reorder previously moved Matras to correct position*/
1803 for (i = s->start; i < s->base; i++)
1804 {
1805 if (lexical(pwChar[i]) == lex_Matra_pre)
1806 {
1807 int j;
1808 int g_start = g->start + i - s->start;
1809 if (g_start < g->base -1 )
1810 {
1811 WCHAR og = glyphs[g_start];
1812 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1813 for (j = g_start; j < g->base-1; j++)
1814 glyphs[j] = glyphs[j+1];
1815 glyphs[g->base-1] = og;
1816 }
1817 }
1818 }
1819 }
1820
1821 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1822 {
1823 if (s->pref >= 0 && g->pref > g->base)
1824 {
1825 int j;
1826 WCHAR og = glyphs[g->pref];
1827 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1828 for (j = g->pref; j > g->base; j--)
1829 glyphs[j] = glyphs[j-1];
1830 glyphs[g->base] = og;
1831 }
1832 }
1833
1834 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1835 {
1836 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1837 if (s->start == s->base && s->base == s->end) return;
1838 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1839
1840 Reorder_Ra_follows_base(pwChar, s, lexical);
1841 Reorder_Matra_precede_base(pwChar, s, lexical);
1842 }
1843
1844 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1845 {
1846 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1847 if (s->start == s->base && s->base == s->end) return;
1848 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1849
1850 Reorder_Ra_follows_matra(pwChar, s, lexical);
1851 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1852 }
1853
1854 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1855 {
1856 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1857 if (s->start == s->base && s->base == s->end) return;
1858 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1859
1860 Reorder_Ra_follows_base(pwChar, s, lexical);
1861 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1862 }
1863
1864 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1865 {
1866 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1867 if (s->start == s->base && s->base == s->end) return;
1868 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1869
1870 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1871 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1872 }
1873
1874 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1875 {
1876 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1877 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1878 if (s->start == s->base && s->base == s->end) return;
1879 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1880
1881 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1882 }
1883
1884 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1885 {
1886 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1887 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1888 if (s->start == s->base && s->base == s->end) return;
1889 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1890
1891 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1892 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1893 }
1894
1895
1896 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1897 {
1898 if (shift == 0)
1899 return;
1900
1901 if (glyph_index->start > index)
1902 glyph_index->start += shift;
1903 if (glyph_index->base > index)
1904 glyph_index->base+= shift;
1905 if (glyph_index->end > index)
1906 glyph_index->end+= shift;
1907 if (glyph_index->ralf > index)
1908 glyph_index->ralf+= shift;
1909 if (glyph_index->blwf > index)
1910 glyph_index->blwf+= shift;
1911 if (glyph_index->pref > index)
1912 glyph_index->pref+= shift;
1913 }
1914
1915 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 )
1916 {
1917 int index = glyph_index->start;
1918
1919 if (!feature)
1920 return;
1921
1922 while(index <= glyph_index->end)
1923 {
1924 INT nextIndex;
1925 INT prevCount = *pcGlyphs;
1926 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1927 if (nextIndex > GSUB_E_NOGLYPH)
1928 {
1929 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1930 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1931 index = nextIndex;
1932 }
1933 else
1934 index++;
1935 }
1936 }
1937
1938 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1939 {
1940 int i = 0;
1941 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)))))
1942 i++;
1943 if (index + i <= end-1)
1944 return index + i;
1945 else
1946 return -1;
1947 }
1948
1949 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)
1950 {
1951 INT index, nextIndex;
1952 INT count,g_offset;
1953
1954 count = syllable->base - syllable->start;
1955
1956 g_offset = 0;
1957 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1958 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1959 {
1960 INT prevCount = *pcGlyphs;
1961 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1962 if (nextIndex > GSUB_E_NOGLYPH)
1963 {
1964 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1965 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1966 g_offset += (*pcGlyphs - prevCount);
1967 }
1968
1969 index+=2;
1970 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1971 }
1972 }
1973
1974 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)
1975 {
1976 INT nextIndex;
1977 INT prevCount = *pcGlyphs;
1978
1979 if (syllable->ralf >= 0)
1980 {
1981 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1982 if (nextIndex > GSUB_E_NOGLYPH)
1983 {
1984 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1985 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1986 }
1987 }
1988 }
1989
1990 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1991 {
1992 int i = 0;
1993 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1994 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1995 is_consonant(lexical(pwChars[index+i+1])))))
1996 i++;
1997 if (index + i <= end-1)
1998 return index+i;
1999 else
2000 return -1;
2001 }
2002
2003 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)
2004 {
2005 INT index, nextIndex;
2006 INT count, g_offset=0;
2007 INT ralf = syllable->ralf;
2008
2009 count = syllable->end - syllable->base;
2010
2011 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2012
2013 while (index >= 0)
2014 {
2015 INT prevCount = *pcGlyphs;
2016 if (ralf >=0 && ralf < index)
2017 {
2018 g_offset--;
2019 ralf = -1;
2020 }
2021
2022 if (!modern)
2023 {
2024 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2025 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2026 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2027 }
2028
2029 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2030 if (nextIndex > GSUB_E_NOGLYPH)
2031 {
2032 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2033 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2034 g_offset += (*pcGlyphs - prevCount);
2035 }
2036 else if (!modern)
2037 {
2038 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2039 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2040 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2041 }
2042
2043 index+=2;
2044 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2045 }
2046 }
2047
2048 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)
2049 {
2050 int c;
2051 int overall_shift = 0;
2052 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2053 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2054 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2055 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2056 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2057 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2058 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2059 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2060 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2061 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2062 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2063 IndicSyllable glyph_indexs;
2064
2065 for (c = 0; c < syllable_count; c++)
2066 {
2067 int old_end;
2068 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2069 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2070 old_end = glyph_indexs.end;
2071
2072 if (locl)
2073 {
2074 TRACE("applying feature locl\n");
2075 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2076 }
2077 if (nukt)
2078 {
2079 TRACE("applying feature nukt\n");
2080 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2081 }
2082 if (akhn)
2083 {
2084 TRACE("applying feature akhn\n");
2085 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2086 }
2087
2088 if (rphf)
2089 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2090 if (rkrf)
2091 {
2092 TRACE("applying feature rkrf\n");
2093 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2094 }
2095 if (pref)
2096 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2097 if (blwf)
2098 {
2099 if (!modern)
2100 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2101
2102 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2103
2104 }
2105 if (half)
2106 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2107 if (pstf)
2108 {
2109 TRACE("applying feature pstf\n");
2110 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2111 }
2112 if (vatu)
2113 {
2114 TRACE("applying feature vatu\n");
2115 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2116 }
2117 if (cjct)
2118 {
2119 TRACE("applying feature cjct\n");
2120 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2121 }
2122
2123 if (second_reorder)
2124 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2125
2126 overall_shift += glyph_indexs.end - old_end;
2127 }
2128 }
2129
2130 static inline int unicode_lex(WCHAR c)
2131 {
2132 int type;
2133
2134 if (!c) return lex_Generic;
2135 if (c == 0x200D) return lex_ZWJ;
2136 if (c == 0x200C) return lex_ZWNJ;
2137 if (c == 0x00A0) return lex_NBSP;
2138
2139 type = get_table_entry( indic_syllabic_table, c );
2140
2141 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2142
2143 switch( type )
2144 {
2145 case 0x0d07: /* Unknown */
2146 case 0x0e07: /* Unknwon */
2147 default: return lex_Generic;
2148 case 0x0001:
2149 case 0x0002:
2150 case 0x0011:
2151 case 0x0012:
2152 case 0x0013:
2153 case 0x0014: return lex_Modifier;
2154 case 0x0003:
2155 case 0x0009:
2156 case 0x000a:
2157 case 0x000b:
2158 case 0x000d:
2159 case 0x000e:
2160 case 0x000f:
2161 case 0x0010: return lex_Consonant;
2162 case 0x0004: return lex_Nukta;
2163 case 0x0005: return lex_Halant;
2164 case 0x0006:
2165 case 0x0008: return lex_Vowel;
2166 case 0x0007:
2167 case 0x0107: return lex_Matra_post;
2168 case 0x0207:
2169 case 0x0307: return lex_Matra_pre;
2170 case 0x0807:
2171 case 0x0907:
2172 case 0x0a07:
2173 case 0x0b07:
2174 case 0x0c07:
2175 case 0x0407: return lex_Composed_Vowel;
2176 case 0x0507: return lex_Matra_above;
2177 case 0x0607: return lex_Matra_below;
2178 case 0x000c:
2179 case 0x0015: return lex_Ra;
2180 };
2181 }
2182
2183 static int sinhala_lex(WCHAR c)
2184 {
2185 switch (c)
2186 {
2187 case 0x0DDA:
2188 case 0x0DDD:
2189 case 0x0DDC:
2190 case 0x0DDE: return lex_Matra_post;
2191 default:
2192 return unicode_lex(c);
2193 }
2194 }
2195
2196 static const VowelComponents Sinhala_vowels[] = {
2197 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2198 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2199 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2200 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2201 {0x0000, {0x0000,0x0000,0x0}}};
2202
2203 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2204 {
2205 int cCount = cChars;
2206 int i;
2207 WCHAR *input;
2208 IndicSyllable *syllables = NULL;
2209 int syllable_count = 0;
2210
2211 if (*pcGlyphs != cChars)
2212 {
2213 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2214 return;
2215 }
2216
2217 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2218
2219 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2220
2221 /* Step 1: Decompose multi part vowels */
2222 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2223
2224 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2225
2226 /* Step 2: Reorder within Syllables */
2227 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2228 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2229
2230 /* Step 3: Strip dangling joiners */
2231 for (i = 0; i < cCount; i++)
2232 {
2233 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2234 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2235 input[i] = 0x0020;
2236 }
2237
2238 /* Step 4: Base Form application to syllables */
2239 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2240 *pcGlyphs = cCount;
2241 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2242
2243 HeapFree(GetProcessHeap(),0,input);
2244 HeapFree(GetProcessHeap(),0,syllables);
2245 }
2246
2247 static int devanagari_lex(WCHAR c)
2248 {
2249 switch (c)
2250 {
2251 case 0x0930: return lex_Ra;
2252 default:
2253 return unicode_lex(c);
2254 }
2255 }
2256
2257 static const ConsonantComponents Devanagari_consonants[] ={
2258 {{0x0928, 0x093C, 0x00000}, 0x0929},
2259 {{0x0930, 0x093C, 0x00000}, 0x0931},
2260 {{0x0933, 0x093C, 0x00000}, 0x0934},
2261 {{0x0915, 0x093C, 0x00000}, 0x0958},
2262 {{0x0916, 0x093C, 0x00000}, 0x0959},
2263 {{0x0917, 0x093C, 0x00000}, 0x095A},
2264 {{0x091C, 0x093C, 0x00000}, 0x095B},
2265 {{0x0921, 0x093C, 0x00000}, 0x095C},
2266 {{0x0922, 0x093C, 0x00000}, 0x095D},
2267 {{0x092B, 0x093C, 0x00000}, 0x095E},
2268 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2269
2270 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2271 {
2272 int cCount = cChars;
2273 WCHAR *input;
2274 IndicSyllable *syllables = NULL;
2275 int syllable_count = 0;
2276 BOOL modern = get_GSUB_Indic2(psa, psc);
2277
2278 if (*pcGlyphs != cChars)
2279 {
2280 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2281 return;
2282 }
2283
2284 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2285 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2286
2287 /* Step 1: Compose Consonant and Nukta */
2288 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2289 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2290
2291 /* Step 2: Reorder within Syllables */
2292 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2293 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2294 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2295 *pcGlyphs = cCount;
2296
2297 /* Step 3: Base Form application to syllables */
2298 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2299
2300 HeapFree(GetProcessHeap(),0,input);
2301 HeapFree(GetProcessHeap(),0,syllables);
2302 }
2303
2304 static int bengali_lex(WCHAR c)
2305 {
2306 switch (c)
2307 {
2308 case 0x09B0: return lex_Ra;
2309 default:
2310 return unicode_lex(c);
2311 }
2312 }
2313
2314 static const VowelComponents Bengali_vowels[] = {
2315 {0x09CB, {0x09C7,0x09BE,0x0000}},
2316 {0x09CC, {0x09C7,0x09D7,0x0000}},
2317 {0x0000, {0x0000,0x0000,0x0000}}};
2318
2319 static const ConsonantComponents Bengali_consonants[] = {
2320 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2321 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2322 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2323 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2324 {{0x0000,0x0000,0x0000}, 0x0000}};
2325
2326 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2327 {
2328 int cCount = cChars;
2329 WCHAR *input;
2330 IndicSyllable *syllables = NULL;
2331 int syllable_count = 0;
2332 BOOL modern = get_GSUB_Indic2(psa, psc);
2333
2334 if (*pcGlyphs != cChars)
2335 {
2336 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2337 return;
2338 }
2339
2340 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2341 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2342
2343 /* Step 1: Decompose Vowels and Compose Consonants */
2344 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2345 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2346 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2347
2348 /* Step 2: Reorder within Syllables */
2349 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2350 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2351 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2352 *pcGlyphs = cCount;
2353
2354 /* Step 3: Initial form is only applied to the beginning of words */
2355 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2356 {
2357 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2358 {
2359 int index = cCount;
2360 int gCount = 1;
2361 if (index > 0) index++;
2362
2363 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2364 }
2365 }
2366
2367 /* Step 4: Base Form application to syllables */
2368 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2369
2370 HeapFree(GetProcessHeap(),0,input);
2371 HeapFree(GetProcessHeap(),0,syllables);
2372 }
2373
2374 static int gurmukhi_lex(WCHAR c)
2375 {
2376 if (c == 0x0A71)
2377 return lex_Modifier;
2378 else
2379 return unicode_lex(c);
2380 }
2381
2382 static const ConsonantComponents Gurmukhi_consonants[] = {
2383 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2384 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2385 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2386 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2387 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2388 {{0x0000,0x0000,0x0000}, 0x0000}};
2389
2390 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2391 {
2392 int cCount = cChars;
2393 WCHAR *input;
2394 IndicSyllable *syllables = NULL;
2395 int syllable_count = 0;
2396 BOOL modern = get_GSUB_Indic2(psa, psc);
2397
2398 if (*pcGlyphs != cChars)
2399 {
2400 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2401 return;
2402 }
2403
2404 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2405 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2406
2407 /* Step 1: Compose Consonants */
2408 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2409 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2410
2411 /* Step 2: Reorder within Syllables */
2412 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2413 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2414 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2415 *pcGlyphs = cCount;
2416
2417 /* Step 3: Base Form application to syllables */
2418 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2419
2420 HeapFree(GetProcessHeap(),0,input);
2421 HeapFree(GetProcessHeap(),0,syllables);
2422 }
2423
2424 static int gujarati_lex(WCHAR c)
2425 {
2426 switch (c)
2427 {
2428 case 0x0AB0: return lex_Ra;
2429 default:
2430 return unicode_lex(c);
2431 }
2432 }
2433
2434 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2435 {
2436 int cCount = cChars;
2437 WCHAR *input;
2438 IndicSyllable *syllables = NULL;
2439 int syllable_count = 0;
2440 BOOL modern = get_GSUB_Indic2(psa, psc);
2441
2442 if (*pcGlyphs != cChars)
2443 {
2444 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2445 return;
2446 }
2447
2448 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2449 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2450
2451 /* Step 1: Reorder within Syllables */
2452 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2453 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2454 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2455 *pcGlyphs = cCount;
2456
2457 /* Step 2: Base Form application to syllables */
2458 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2459
2460 HeapFree(GetProcessHeap(),0,input);
2461 HeapFree(GetProcessHeap(),0,syllables);
2462 }
2463
2464 static int oriya_lex(WCHAR c)
2465 {
2466 switch (c)
2467 {
2468 case 0x0B30: return lex_Ra;
2469 default:
2470 return unicode_lex(c);
2471 }
2472 }
2473
2474 static const VowelComponents Oriya_vowels[] = {
2475 {0x0B48, {0x0B47,0x0B56,0x0000}},
2476 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2477 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2478 {0x0000, {0x0000,0x0000,0x0000}}};
2479
2480 static const ConsonantComponents Oriya_consonants[] = {
2481 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2482 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2483 {{0x0000,0x0000,0x0000}, 0x0000}};
2484
2485 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2486 {
2487 int cCount = cChars;
2488 WCHAR *input;
2489 IndicSyllable *syllables = NULL;
2490 int syllable_count = 0;
2491 BOOL modern = get_GSUB_Indic2(psa, psc);
2492
2493 if (*pcGlyphs != cChars)
2494 {
2495 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2496 return;
2497 }
2498
2499 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2500 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2501
2502 /* Step 1: Decompose Vowels and Compose Consonants */
2503 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2504 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2505 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2506
2507 /* Step 2: Reorder within Syllables */
2508 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2509 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2510 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2511 *pcGlyphs = cCount;
2512
2513 /* Step 3: Base Form application to syllables */
2514 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2515
2516 HeapFree(GetProcessHeap(),0,input);
2517 HeapFree(GetProcessHeap(),0,syllables);
2518 }
2519
2520 static int tamil_lex(WCHAR c)
2521 {
2522 return unicode_lex(c);
2523 }
2524
2525 static const VowelComponents Tamil_vowels[] = {
2526 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2527 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2528 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2529 {0x0000, {0x0000,0x0000,0x0000}}};
2530
2531 static const ConsonantComponents Tamil_consonants[] = {
2532 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2533 {{0x0000,0x0000,0x0000}, 0x0000}};
2534
2535 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2536 {
2537 int cCount = cChars;
2538 WCHAR *input;
2539 IndicSyllable *syllables = NULL;
2540 int syllable_count = 0;
2541 BOOL modern = get_GSUB_Indic2(psa, psc);
2542
2543 if (*pcGlyphs != cChars)
2544 {
2545 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2546 return;
2547 }
2548
2549 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2550 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2551
2552 /* Step 1: Decompose Vowels and Compose Consonants */
2553 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2554 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2555 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2556
2557 /* Step 2: Reorder within Syllables */
2558 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2559 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2560 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2561 *pcGlyphs = cCount;
2562
2563 /* Step 3: Base Form application to syllables */
2564 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2565
2566 HeapFree(GetProcessHeap(),0,input);
2567 HeapFree(GetProcessHeap(),0,syllables);
2568 }
2569
2570 static int telugu_lex(WCHAR c)
2571 {
2572 switch (c)
2573 {
2574 case 0x0C43:
2575 case 0x0C44: return lex_Modifier;
2576 default:
2577 return unicode_lex(c);
2578 }
2579 }
2580
2581 static const VowelComponents Telugu_vowels[] = {
2582 {0x0C48, {0x0C46,0x0C56,0x0000}},
2583 {0x0000, {0x0000,0x0000,0x0000}}};
2584
2585 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2586 {
2587 int cCount = cChars;
2588 WCHAR *input;
2589 IndicSyllable *syllables = NULL;
2590 int syllable_count = 0;
2591 BOOL modern = get_GSUB_Indic2(psa, psc);
2592
2593 if (*pcGlyphs != cChars)
2594 {
2595 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2596 return;
2597 }
2598
2599 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2600 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2601
2602 /* Step 1: Decompose Vowels */
2603 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2604 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2605
2606 /* Step 2: Reorder within Syllables */
2607 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2608 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2609 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2610 *pcGlyphs = cCount;
2611
2612 /* Step 3: Base Form application to syllables */
2613 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2614
2615 HeapFree(GetProcessHeap(),0,input);
2616 HeapFree(GetProcessHeap(),0,syllables);
2617 }
2618
2619 static int kannada_lex(WCHAR c)
2620 {
2621 switch (c)
2622 {
2623 case 0x0CB0: return lex_Ra;
2624 default:
2625 return unicode_lex(c);
2626 }
2627 }
2628
2629 static const VowelComponents Kannada_vowels[] = {
2630 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2631 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2632 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2633 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2634 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2635 {0x0000, {0x0000,0x0000,0x0000}}};
2636
2637 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2638 {
2639 int cCount = cChars;
2640 WCHAR *input;
2641 IndicSyllable *syllables = NULL;
2642 int syllable_count = 0;
2643 BOOL modern = get_GSUB_Indic2(psa, psc);
2644
2645 if (*pcGlyphs != cChars)
2646 {
2647 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2648 return;
2649 }
2650
2651 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2652 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2653
2654 /* Step 1: Decompose Vowels */
2655 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2656 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2657
2658 /* Step 2: Reorder within Syllables */
2659 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2660 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2661 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2662 *pcGlyphs = cCount;
2663
2664 /* Step 3: Base Form application to syllables */
2665 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2666
2667 HeapFree(GetProcessHeap(),0,input);
2668 HeapFree(GetProcessHeap(),0,syllables);
2669 }
2670
2671 static int malayalam_lex(WCHAR c)
2672 {
2673 return unicode_lex(c);
2674 }
2675
2676 static const VowelComponents Malayalam_vowels[] = {
2677 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2678 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2679 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2680 {0x0000, {0x0000,0x0000,0x0000}}};
2681
2682 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2683 {
2684 int cCount = cChars;
2685 WCHAR *input;
2686 IndicSyllable *syllables = NULL;
2687 int syllable_count = 0;
2688 BOOL modern = get_GSUB_Indic2(psa, psc);
2689
2690 if (*pcGlyphs != cChars)
2691 {
2692 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2693 return;
2694 }
2695
2696 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2697 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2698
2699 /* Step 1: Decompose Vowels */
2700 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2701 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2702
2703 /* Step 2: Reorder within Syllables */
2704 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2705 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2706 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2707 *pcGlyphs = cCount;
2708
2709 /* Step 3: Base Form application to syllables */
2710 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2711
2712 HeapFree(GetProcessHeap(),0,input);
2713 HeapFree(GetProcessHeap(),0,syllables);
2714 }
2715
2716 static int khmer_lex(WCHAR c)