74c7a387847ac19ee1f5df809056cb7ed63041a4
[reactos.git] / reactos / dll / win32 / usp10 / shape.c
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
3 *
4 * Copyright 2010 CodeWeavers, Aric Stewart
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 */
21
22 #include "usp10_internal.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
25
26 #define FIRST_ARABIC_CHAR 0x0600
27 #define LAST_ARABIC_CHAR 0x06ff
28
29 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
30 WCHAR*, INT, WORD*, INT*, INT, WORD*);
31
32 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
33 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
34 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
35 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
36 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
37 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
38 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
39 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
40 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
41 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
42 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
43 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52
53 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
54
55 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
56 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
57 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
58 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
59 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
60 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
61 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
62 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
63 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
64 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
65 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
66 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
67 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
68 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
73 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74
75 extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
76 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
77 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
78
79 enum joining_types {
80 jtU,
81 jtT,
82 jtR,
83 jtL,
84 jtD,
85 jtC
86 };
87
88 enum joined_forms {
89 Xn=0,
90 Xr,
91 Xl,
92 Xm,
93 /* Syriac Alaph */
94 Afj,
95 Afn,
96 Afx
97 };
98
99 typedef struct tagVowelComponents
100 {
101 WCHAR base;
102 WCHAR parts[3];
103 } VowelComponents;
104
105 typedef struct tagConsonantComponents
106 {
107 WCHAR parts[3];
108 WCHAR output;
109 } ConsonantComponents;
110
111 typedef void (*second_reorder_function)(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 int char_index;
1064 int glyph_index;
1065
1066 if (*pcGlyphs != cChars)
1067 {
1068 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1069 return;
1070 }
1071
1072 if (!psa->fLogicalOrder && psa->fRTL)
1073 {
1074 dirR = 1;
1075 dirL = -1;
1076 }
1077 else
1078 {
1079 dirR = -1;
1080 dirL = 1;
1081 }
1082
1083 load_ot_tables(hdc, psc);
1084
1085 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1086 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1087
1088 for (i = 0; i < cChars; i++)
1089 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1090
1091 for (i = 0; i < cChars; i++)
1092 {
1093 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1094 context_shape[i] = Xr;
1095 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1096 context_shape[i] = Xl;
1097 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)))
1098 context_shape[i] = Xm;
1099 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1100 context_shape[i] = Xr;
1101 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1102 context_shape[i] = Xl;
1103 else
1104 context_shape[i] = Xn;
1105 }
1106
1107 /* Contextual Shaping */
1108 if (dirL > 0)
1109 char_index = glyph_index = 0;
1110 else
1111 char_index = glyph_index = cChars-1;
1112
1113 while(char_index < cChars && char_index >= 0)
1114 {
1115 BOOL shaped = FALSE;
1116
1117 if (psc->GSUB_Table)
1118 {
1119 INT nextIndex, offset = 0;
1120 INT prevCount = *pcGlyphs;
1121
1122 /* Apply CCMP first */
1123 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1124
1125 if (prevCount != *pcGlyphs)
1126 {
1127 offset = *pcGlyphs - prevCount;
1128 if (dirL < 0)
1129 glyph_index -= offset * dirL;
1130 }
1131
1132 /* Apply the contextual feature */
1133 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1134
1135 if (nextIndex > GSUB_E_NOGLYPH)
1136 {
1137 UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1138 char_index += dirL;
1139 if (!offset)
1140 glyph_index = nextIndex;
1141 else
1142 {
1143 offset = *pcGlyphs - prevCount;
1144 glyph_index += dirL * (offset + 1);
1145 }
1146 }
1147 shaped = (nextIndex > GSUB_E_NOGLYPH);
1148 }
1149
1150 if (!shaped)
1151 {
1152 if (context_shape[char_index] == Xn)
1153 {
1154 WORD newGlyph = pwOutGlyphs[glyph_index];
1155 if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
1156 {
1157 /* fall back to presentation form B */
1158 WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
1159 if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1160 pwOutGlyphs[glyph_index] = newGlyph;
1161 }
1162 }
1163 char_index += dirL;
1164 glyph_index += dirL;
1165 }
1166 }
1167
1168 HeapFree(GetProcessHeap(),0,context_shape);
1169 HeapFree(GetProcessHeap(),0,context_type);
1170
1171 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1172 }
1173
1174 static int combining_lexical_Hebrew(WCHAR c)
1175 {
1176 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};
1177
1178 switch(c)
1179 {
1180 case 0x05B0:
1181 case 0x05B1:
1182 case 0x05B2:
1183 case 0x05B3:
1184 case 0x05B4:
1185 case 0x05B5:
1186 case 0x05B6:
1187 case 0x05BB: return Hebr_DIAC;
1188 case 0x0599:
1189 case 0x05A1:
1190 case 0x05A9:
1191 case 0x05AE: return Hebr_CANT1;
1192 case 0x0597:
1193 case 0x05A8:
1194 case 0x05AC: return Hebr_CANT2;
1195 case 0x0592:
1196 case 0x0593:
1197 case 0x0594:
1198 case 0x0595:
1199 case 0x05A7:
1200 case 0x05AB: return Hebr_CANT3;
1201 case 0x0598:
1202 case 0x059C:
1203 case 0x059E:
1204 case 0x059F: return Hebr_CANT4;
1205 case 0x059D:
1206 case 0x05A0: return Hebr_CANT5;
1207 case 0x059B:
1208 case 0x05A5: return Hebr_CANT6;
1209 case 0x0591:
1210 case 0x05A3:
1211 case 0x05A6: return Hebr_CANT7;
1212 case 0x0596:
1213 case 0x05A4:
1214 case 0x05AA: return Hebr_CANT8;
1215 case 0x059A:
1216 case 0x05AD: return Hebr_CANT9;
1217 case 0x05AF: return Hebr_CANT10;
1218 case 0x05BC: return Hebr_DAGESH;
1219 case 0x05C4: return Hebr_DOTABV;
1220 case 0x05B9: return Hebr_HOLAM;
1221 case 0x05BD: return Hebr_METEG;
1222 case 0x05B7: return Hebr_PATAH;
1223 case 0x05B8: return Hebr_QAMATS;
1224 case 0x05BF: return Hebr_RAFE;
1225 case 0x05C1:
1226 case 0x05C2: return Hebr_SHINSIN;
1227 default: return Hebr_Norm;
1228 }
1229 }
1230
1231 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1232 {
1233 INT dirL;
1234
1235 if (*pcGlyphs != cChars)
1236 {
1237 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1238 return;
1239 }
1240
1241 if (!psa->fLogicalOrder && psa->fRTL)
1242 dirL = -1;
1243 else
1244 dirL = 1;
1245
1246 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1247 }
1248
1249 /*
1250 * ContextualShape_Syriac
1251 */
1252
1253 static int combining_lexical_Syriac(WCHAR c)
1254 {
1255 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};
1256
1257 switch(c)
1258 {
1259 case 0x730:
1260 case 0x733:
1261 case 0x736:
1262 case 0x73A:
1263 case 0x73D: return Syriac_DIAC1;
1264 case 0x731:
1265 case 0x734:
1266 case 0x737:
1267 case 0x73B:
1268 case 0x73E: return Syriac_DIAC2;
1269 case 0x740:
1270 case 0x749:
1271 case 0x74A: return Syriac_DIAC3;
1272 case 0x732:
1273 case 0x735:
1274 case 0x73F: return Syriac_DIAC4;
1275 case 0x738:
1276 case 0x739:
1277 case 0x73C: return Syriac_DIAC5;
1278 case 0x741:
1279 case 0x30A: return Syriac_DIAC6;
1280 case 0x742:
1281 case 0x325: return Syriac_DIAC7;
1282 case 0x747:
1283 case 0x303: return Syriac_DIAC8;
1284 case 0x748:
1285 case 0x32D:
1286 case 0x32E:
1287 case 0x330:
1288 case 0x331: return Syriac_DIAC9;
1289 case 0x308: return Syriac_DIAC10;
1290 case 0x304: return Syriac_DIAC11;
1291 case 0x307: return Syriac_DIAC12;
1292 case 0x323: return Syriac_DIAC13;
1293 case 0x743: return Syriac_DIAC14;
1294 case 0x744: return Syriac_DIAC15;
1295 case 0x745: return Syriac_DIAC16;
1296 case 0x746: return Syriac_DIAC17;
1297 default: return Syriac_Norm;
1298 }
1299 }
1300
1301 #define ALAPH 0x710
1302 #define DALATH 0x715
1303 #define RISH 0x72A
1304
1305 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1306 {
1307 CHAR *context_type;
1308 INT *context_shape;
1309 INT dirR, dirL;
1310 int i;
1311 int char_index;
1312 int glyph_index;
1313
1314 if (*pcGlyphs != cChars)
1315 {
1316 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1317 return;
1318 }
1319
1320 if (!psa->fLogicalOrder && psa->fRTL)
1321 {
1322 dirR = 1;
1323 dirL = -1;
1324 }
1325 else
1326 {
1327 dirR = -1;
1328 dirL = 1;
1329 }
1330
1331 load_ot_tables(hdc, psc);
1332
1333 if (!psc->GSUB_Table)
1334 return;
1335
1336 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1337 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1338
1339 for (i = 0; i < cChars; i++)
1340 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1341
1342 for (i = 0; i < cChars; i++)
1343 {
1344 if (pwcChars[i] == ALAPH)
1345 {
1346 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1347
1348 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1349 context_shape[i] = Afj;
1350 else if ( rchar != DALATH && rchar != RISH &&
1351 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1352 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1353 context_shape[i] = Afn;
1354 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1355 context_shape[i] = Afx;
1356 else
1357 context_shape[i] = Xn;
1358 }
1359 else if (context_type[i] == jtR &&
1360 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1361 context_shape[i] = Xr;
1362 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1363 context_shape[i] = Xl;
1364 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)))
1365 context_shape[i] = Xm;
1366 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1367 context_shape[i] = Xr;
1368 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1369 context_shape[i] = Xl;
1370 else
1371 context_shape[i] = Xn;
1372 }
1373
1374 /* Contextual Shaping */
1375 if (dirL > 0)
1376 char_index = glyph_index = 0;
1377 else
1378 char_index = glyph_index = cChars-1;
1379
1380 while(char_index < cChars && char_index >= 0)
1381 {
1382 INT nextIndex, offset = 0;
1383 INT prevCount = *pcGlyphs;
1384
1385 /* Apply CCMP first */
1386 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1387
1388 if (prevCount != *pcGlyphs)
1389 {
1390 offset = *pcGlyphs - prevCount;
1391 if (dirL < 0)
1392 glyph_index -= offset * dirL;
1393 }
1394
1395 /* Apply the contextual feature */
1396 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1397 if (nextIndex > GSUB_E_NOGLYPH)
1398 {
1399 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1400 char_index += dirL;
1401 if (!offset)
1402 glyph_index = nextIndex;
1403 else
1404 {
1405 offset = *pcGlyphs - prevCount;
1406 glyph_index += dirL * (offset + 1);
1407 }
1408 }
1409 else
1410 {
1411 char_index += dirL;
1412 glyph_index += dirL;
1413 }
1414 }
1415
1416 HeapFree(GetProcessHeap(),0,context_shape);
1417 HeapFree(GetProcessHeap(),0,context_type);
1418
1419 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1420 }
1421
1422 static int combining_lexical_Thaana(WCHAR c)
1423 {
1424 enum {Thaana_Norm=0, Thaana_FILI};
1425
1426 switch(c)
1427 {
1428 case 0x7A6:
1429 case 0x7A7:
1430 case 0x7A8:
1431 case 0x7A9:
1432 case 0x7AA:
1433 case 0x7AB:
1434 case 0x7AC:
1435 case 0x7AD:
1436 case 0x7AE:
1437 case 0x7AF: return Thaana_FILI;
1438 default: return Thaana_Norm;
1439 }
1440 }
1441
1442 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1443 {
1444 INT dirL;
1445
1446 if (*pcGlyphs != cChars)
1447 {
1448 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1449 return;
1450 }
1451
1452 if (!psa->fLogicalOrder && psa->fRTL)
1453 dirL = -1;
1454 else
1455 dirL = 1;
1456
1457 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1458 }
1459
1460 /*
1461 * ContextualShape_Phags_pa
1462 */
1463
1464 #define phags_pa_CANDRABINDU 0xA873
1465 #define phags_pa_START 0xA840
1466 #define phags_pa_END 0xA87F
1467
1468 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1469 {
1470 INT *context_shape;
1471 INT dirR, dirL;
1472 int i;
1473 int char_index;
1474 int glyph_index;
1475
1476 if (*pcGlyphs != cChars)
1477 {
1478 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1479 return;
1480 }
1481
1482 if (!psa->fLogicalOrder && psa->fRTL)
1483 {
1484 dirR = 1;
1485 dirL = -1;
1486 }
1487 else
1488 {
1489 dirR = -1;
1490 dirL = 1;
1491 }
1492
1493 load_ot_tables(hdc, psc);
1494
1495 if (!psc->GSUB_Table)
1496 return;
1497
1498 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1499
1500 for (i = 0; i < cChars; i++)
1501 {
1502 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1503 {
1504 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1505 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1506 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1507 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1508
1509 if (jrchar && jlchar)
1510 context_shape[i] = Xm;
1511 else if (jrchar)
1512 context_shape[i] = Xr;
1513 else if (jlchar)
1514 context_shape[i] = Xl;
1515 else
1516 context_shape[i] = Xn;
1517 }
1518 else
1519 context_shape[i] = -1;
1520 }
1521
1522 /* Contextual Shaping */
1523 if (dirL > 0)
1524 char_index = glyph_index = 0;
1525 else
1526 char_index = glyph_index = cChars-1;
1527
1528 while(char_index < cChars && char_index >= 0)
1529 {
1530 if (context_shape[char_index] >= 0)
1531 {
1532 INT nextIndex;
1533 INT prevCount = *pcGlyphs;
1534 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1535
1536 if (nextIndex > GSUB_E_NOGLYPH)
1537 {
1538 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1539 glyph_index = nextIndex;
1540 char_index += dirL;
1541 }
1542 else
1543 {
1544 char_index += dirL;
1545 glyph_index += dirL;
1546 }
1547 }
1548 else
1549 {
1550 char_index += dirL;
1551 glyph_index += dirL;
1552 }
1553 }
1554
1555 HeapFree(GetProcessHeap(),0,context_shape);
1556 }
1557
1558 static int combining_lexical_Thai(WCHAR c)
1559 {
1560 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1561
1562 switch(c)
1563 {
1564 case 0xE31:
1565 case 0xE34:
1566 case 0xE35:
1567 case 0xE36:
1568 case 0xE37: return Thai_ABOVE1;
1569 case 0xE47:
1570 case 0xE4D: return Thai_ABOVE2;
1571 case 0xE48:
1572 case 0xE49:
1573 case 0xE4A:
1574 case 0xE4B: return Thai_ABOVE3;
1575 case 0xE4C:
1576 case 0xE4E: return Thai_ABOVE4;
1577 case 0xE38:
1578 case 0xE39: return Thai_BELOW1;
1579 case 0xE3A: return Thai_BELOW2;
1580 case 0xE33: return Thai_AM;
1581 default: return Thai_Norm;
1582 }
1583 }
1584
1585 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1586 {
1587 INT dirL;
1588
1589 if (*pcGlyphs != cChars)
1590 {
1591 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1592 return;
1593 }
1594
1595 if (!psa->fLogicalOrder && psa->fRTL)
1596 dirL = -1;
1597 else
1598 dirL = 1;
1599
1600 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1601 }
1602
1603 static int combining_lexical_Lao(WCHAR c)
1604 {
1605 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1606
1607 switch(c)
1608 {
1609 case 0xEB1:
1610 case 0xEB4:
1611 case 0xEB5:
1612 case 0xEB6:
1613 case 0xEB7:
1614 case 0xEBB:
1615 case 0xECD: return Lao_ABOVE1;
1616 case 0xEC8:
1617 case 0xEC9:
1618 case 0xECA:
1619 case 0xECB:
1620 case 0xECC: return Lao_ABOVE2;
1621 case 0xEBC: return Lao_BELOW1;
1622 case 0xEB8:
1623 case 0xEB9: return Lao_BELOW2;
1624 case 0xEB3: return Lao_AM;
1625 default: return Lao_Norm;
1626 }
1627 }
1628
1629 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1630 {
1631 INT dirL;
1632
1633 if (*pcGlyphs != cChars)
1634 {
1635 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1636 return;
1637 }
1638
1639 if (!psa->fLogicalOrder && psa->fRTL)
1640 dirL = -1;
1641 else
1642 dirL = 1;
1643
1644 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1645 }
1646
1647 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1648 {
1649 int i;
1650
1651 /* Replace */
1652 pwOutChars[cWalk] = replacements[0];
1653 cWalk=cWalk+1;
1654
1655 /* Insert */
1656 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1657 {
1658 int j;
1659 for (j = *pcChars; j > cWalk; j--)
1660 pwOutChars[j] = pwOutChars[j-1];
1661 *pcChars= *pcChars+1;
1662 pwOutChars[cWalk] = replacements[i];
1663 cWalk = cWalk+1;
1664 }
1665 }
1666
1667 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1668 {
1669 int i;
1670 int cWalk;
1671
1672 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1673 {
1674 for (i = 0; vowels[i].base != 0x0; i++)
1675 {
1676 if (pwOutChars[cWalk] == vowels[i].base)
1677 {
1678 int o = 0;
1679 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1680 if (vowels[i].parts[1]) { cWalk++; o++; }
1681 if (vowels[i].parts[2]) { cWalk++; o++; }
1682 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1683 break;
1684 }
1685 }
1686 }
1687 }
1688
1689 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1690 {
1691 int i;
1692 int offset = 0;
1693 int cWalk;
1694
1695 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1696 {
1697 for (i = 0; consonants[i].output!= 0x0; i++)
1698 {
1699 int j;
1700 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1701 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1702 break;
1703
1704 if (consonants[i].parts[j]==0x0) /* matched all */
1705 {
1706 int k;
1707 j--;
1708 pwOutChars[cWalk] = consonants[i].output;
1709 for(k = cWalk+1; k < *pcChars - j; k++)
1710 pwOutChars[k] = pwOutChars[k+j];
1711 *pcChars = *pcChars - j;
1712 for (k = j ; k > 0; k--)
1713 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1714 offset += j;
1715 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1716 pwLogClust[k]--;
1717 break;
1718 }
1719 }
1720 cWalk++;
1721 }
1722 }
1723
1724 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1725 {
1726 if (s->ralf >= 0)
1727 {
1728 int j;
1729 WORD Ra = pwChar[s->start];
1730 WORD H = pwChar[s->start+1];
1731
1732 TRACE("Doing reorder of Ra to %i\n",s->base);
1733 for (j = s->start; j < s->base-1; j++)
1734 pwChar[j] = pwChar[j+2];
1735 pwChar[s->base-1] = Ra;
1736 pwChar[s->base] = H;
1737
1738 s->ralf = s->base-1;
1739 s->base -= 2;
1740 }
1741 }
1742
1743 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1744 {
1745 if (s->ralf >= 0)
1746 {
1747 int j,loc;
1748 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1749 WORD Ra = pwChar[s->start];
1750 WORD H = pwChar[s->start+1];
1751 for (loc = s->end; loc > stop; loc--)
1752 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1753 break;
1754
1755 TRACE("Doing reorder of Ra to %i\n",loc);
1756 for (j = s->start; j < loc-1; j++)
1757 pwChar[j] = pwChar[j+2];
1758 pwChar[loc-1] = Ra;
1759 pwChar[loc] = H;
1760
1761 s->ralf = loc-1;
1762 s->base -= 2;
1763 if (s->blwf >= 0) s->blwf -= 2;
1764 if (s->pref >= 0) s->pref -= 2;
1765 }
1766 }
1767
1768 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1769 {
1770 if (s->ralf >= 0)
1771 {
1772 int j;
1773 WORD Ra = pwChar[s->start];
1774 WORD H = pwChar[s->start+1];
1775
1776 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1777 for (j = s->start; j < s->end-1; j++)
1778 pwChar[j] = pwChar[j+2];
1779 pwChar[s->end-1] = Ra;
1780 pwChar[s->end] = H;
1781
1782 s->ralf = s->end-1;
1783 s->base -= 2;
1784 if (s->blwf >= 0) s->blwf -= 2;
1785 if (s->pref >= 0) s->pref -= 2;
1786 }
1787 }
1788
1789 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1790 {
1791 int i;
1792
1793 /* reorder Matras */
1794 if (s->end > s->base)
1795 {
1796 for (i = 1; i <= s->end-s->base; i++)
1797 {
1798 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1799 {
1800 int j;
1801 WCHAR c = pwChar[s->base+i];
1802 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1803 for (j = s->base+i; j > s->base; j--)
1804 pwChar[j] = pwChar[j-1];
1805 pwChar[s->base] = c;
1806
1807 if (s->ralf >= s->base) s->ralf++;
1808 if (s->blwf >= s->base) s->blwf++;
1809 if (s->pref >= s->base) s->pref++;
1810 s->base ++;
1811 }
1812 }
1813 }
1814 }
1815
1816 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1817 {
1818 int i;
1819
1820 /* reorder Matras */
1821 if (s->end > s->base)
1822 {
1823 for (i = 1; i <= s->end-s->base; i++)
1824 {
1825 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1826 {
1827 int j;
1828 WCHAR c = pwChar[s->base+i];
1829 TRACE("Doing reorder of %x to %i\n",c,s->start);
1830 for (j = s->base+i; j > s->start; j--)
1831 pwChar[j] = pwChar[j-1];
1832 pwChar[s->start] = c;
1833
1834 if (s->ralf >= 0) s->ralf++;
1835 if (s->blwf >= 0) s->blwf++;
1836 if (s->pref >= 0) s->pref++;
1837 s->base ++;
1838 }
1839 }
1840 }
1841 }
1842
1843 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1844 {
1845 if (s->blwf >= 0 && g->blwf > g->base)
1846 {
1847 int j,loc;
1848 int g_offset;
1849 for (loc = s->end; loc > s->blwf; loc--)
1850 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1851 break;
1852
1853 g_offset = (loc - s->blwf) - 1;
1854
1855 if (loc != s->blwf)
1856 {
1857 WORD blwf = glyphs[g->blwf];
1858 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1859 /* do not care about the pwChar array anymore, just the glyphs */
1860 for (j = 0; j < g_offset; j++)
1861 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1862 glyphs[g->blwf + g_offset] = blwf;
1863 }
1864 }
1865 }
1866
1867 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1868 {
1869 int i;
1870
1871 /* reorder previously moved Matras to correct position*/
1872 for (i = s->start; i < s->base; i++)
1873 {
1874 if (lexical(pwChar[i]) == lex_Matra_pre)
1875 {
1876 int j;
1877 int g_start = g->start + i - s->start;
1878 if (g_start < g->base -1 )
1879 {
1880 WCHAR og = glyphs[g_start];
1881 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1882 for (j = g_start; j < g->base-1; j++)
1883 glyphs[j] = glyphs[j+1];
1884 glyphs[g->base-1] = og;
1885 }
1886 }
1887 }
1888 }
1889
1890 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1891 {
1892 if (s->pref >= 0 && g->pref > g->base)
1893 {
1894 int j;
1895 WCHAR og = glyphs[g->pref];
1896 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1897 for (j = g->pref; j > g->base; j--)
1898 glyphs[j] = glyphs[j-1];
1899 glyphs[g->base] = og;
1900 }
1901 }
1902
1903 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1904 {
1905 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1906 if (s->start == s->base && s->base == s->end) return;
1907 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1908
1909 Reorder_Ra_follows_base(pwChar, s, lexical);
1910 Reorder_Matra_precede_base(pwChar, s, lexical);
1911 }
1912
1913 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1914 {
1915 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1916 if (s->start == s->base && s->base == s->end) return;
1917 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1918
1919 Reorder_Ra_follows_matra(pwChar, s, lexical);
1920 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1921 }
1922
1923 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1924 {
1925 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1926 if (s->start == s->base && s->base == s->end) return;
1927 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1928
1929 Reorder_Ra_follows_base(pwChar, s, lexical);
1930 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1931 }
1932
1933 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1934 {
1935 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1936 if (s->start == s->base && s->base == s->end) return;
1937 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1938
1939 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1940 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1941 }
1942
1943 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1944 {
1945 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1946 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1947 if (s->start == s->base && s->base == s->end) return;
1948 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1949
1950 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1951 }
1952
1953 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1954 {
1955 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1956 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1957 if (s->start == s->base && s->base == s->end) return;
1958 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1959
1960 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1961 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1962 }
1963
1964
1965 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1966 {
1967 if (shift == 0)
1968 return;
1969
1970 if (glyph_index->start > index)
1971 glyph_index->start += shift;
1972 if (glyph_index->base > index)
1973 glyph_index->base+= shift;
1974 if (glyph_index->end > index)
1975 glyph_index->end+= shift;
1976 if (glyph_index->ralf > index)
1977 glyph_index->ralf+= shift;
1978 if (glyph_index->blwf > index)
1979 glyph_index->blwf+= shift;
1980 if (glyph_index->pref > index)
1981 glyph_index->pref+= shift;
1982 }
1983
1984 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 )
1985 {
1986 int index = glyph_index->start;
1987
1988 if (!feature)
1989 return;
1990
1991 while(index <= glyph_index->end)
1992 {
1993 INT nextIndex;
1994 INT prevCount = *pcGlyphs;
1995 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1996 if (nextIndex > GSUB_E_NOGLYPH)
1997 {
1998 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1999 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2000 index = nextIndex;
2001 }
2002 else
2003 index++;
2004 }
2005 }
2006
2007 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2008 {
2009 int i = 0;
2010 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)))))
2011 i++;
2012 if (index + i <= end-1)
2013 return index + i;
2014 else
2015 return -1;
2016 }
2017
2018 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)
2019 {
2020 INT index, nextIndex;
2021 INT count,g_offset;
2022
2023 count = syllable->base - syllable->start;
2024
2025 g_offset = 0;
2026 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2027 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2028 {
2029 INT prevCount = *pcGlyphs;
2030 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2031 if (nextIndex > GSUB_E_NOGLYPH)
2032 {
2033 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2034 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2035 g_offset += (*pcGlyphs - prevCount);
2036 }
2037
2038 index+=2;
2039 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2040 }
2041 }
2042
2043 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)
2044 {
2045 INT nextIndex;
2046 INT prevCount = *pcGlyphs;
2047
2048 if (syllable->ralf >= 0)
2049 {
2050 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2051 if (nextIndex > GSUB_E_NOGLYPH)
2052 {
2053 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2054 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2055 }
2056 }
2057 }
2058
2059 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2060 {
2061 int i = 0;
2062 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2063 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2064 is_consonant(lexical(pwChars[index+i+1])))))
2065 i++;
2066 if (index + i <= end-1)
2067 return index+i;
2068 else
2069 return -1;
2070 }
2071
2072 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)
2073 {
2074 INT index, nextIndex;
2075 INT count, g_offset=0;
2076 INT ralf = syllable->ralf;
2077
2078 count = syllable->end - syllable->base;
2079
2080 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2081
2082 while (index >= 0)
2083 {
2084 INT prevCount = *pcGlyphs;
2085 if (ralf >=0 && ralf < index)
2086 {
2087 g_offset--;
2088 ralf = -1;
2089 }
2090
2091 if (!modern)
2092 {
2093 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2094 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2095 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2096 }
2097
2098 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2099 if (nextIndex > GSUB_E_NOGLYPH)
2100 {
2101 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2102 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2103 g_offset += (*pcGlyphs - prevCount);
2104 }
2105 else if (!modern)
2106 {
2107 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2108 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2109 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2110 }
2111
2112 index+=2;
2113 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2114 }
2115 }
2116
2117 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)
2118 {
2119 int c;
2120 int overall_shift = 0;
2121 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2122 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2123 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2124 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2125 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2126 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2127 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2128 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2129 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2130 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2131 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2132 IndicSyllable glyph_indexs;
2133
2134 for (c = 0; c < syllable_count; c++)
2135 {
2136 int old_end;
2137 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2138 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2139 old_end = glyph_indexs.end;
2140
2141 if (locl)
2142 {
2143 TRACE("applying feature locl\n");
2144 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2145 }
2146 if (nukt)
2147 {
2148 TRACE("applying feature nukt\n");
2149 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2150 }
2151 if (akhn)
2152 {
2153 TRACE("applying feature akhn\n");
2154 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2155 }
2156
2157 if (rphf)
2158 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2159 if (rkrf)
2160 {
2161 TRACE("applying feature rkrf\n");
2162 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2163 }
2164 if (pref)
2165 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2166 if (blwf)
2167 {
2168 if (!modern)
2169 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2170
2171 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2172
2173 }
2174 if (half)
2175 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2176 if (pstf)
2177 {
2178 TRACE("applying feature pstf\n");
2179 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2180 }
2181 if (vatu)
2182 {
2183 TRACE("applying feature vatu\n");
2184 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2185 }
2186 if (cjct)
2187 {
2188 TRACE("applying feature cjct\n");
2189 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2190 }
2191
2192 if (second_reorder)
2193 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2194
2195 overall_shift += glyph_indexs.end - old_end;
2196 }
2197 }
2198
2199 static inline int unicode_lex(WCHAR c)
2200 {
2201 int type;
2202
2203 if (!c) return lex_Generic;
2204 if (c == 0x200D) return lex_ZWJ;
2205 if (c == 0x200C) return lex_ZWNJ;
2206 if (c == 0x00A0) return lex_NBSP;
2207
2208 type = get_table_entry( indic_syllabic_table, c );
2209
2210 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2211
2212 switch( type )
2213 {
2214 case 0x0d07: /* Unknown */
2215 case 0x0e07: /* Unknown */
2216 default: return lex_Generic;
2217 case 0x0001:
2218 case 0x0002:
2219 case 0x0011:
2220 case 0x0012:
2221 case 0x0013:
2222 case 0x0014: return lex_Modifier;
2223 case 0x0003:
2224 case 0x0009:
2225 case 0x000a:
2226 case 0x000b:
2227 case 0x000d:
2228 case 0x000e:
2229 case 0x000f:
2230 case 0x0010: return lex_Consonant;
2231 case 0x0004: return lex_Nukta;
2232 case 0x0005: return lex_Halant;
2233 case 0x0006:
2234 case 0x0008: return lex_Vowel;
2235 case 0x0007:
2236 case 0x0107: return lex_Matra_post;
2237 case 0x0207:
2238 case 0x0307: return lex_Matra_pre;
2239 case 0x0807:
2240 case 0x0907:
2241 case 0x0a07:
2242 case 0x0b07:
2243 case 0x0c07:
2244 case 0x0407: return lex_Composed_Vowel;
2245 case 0x0507: return lex_Matra_above;
2246 case 0x0607: return lex_Matra_below;
2247 case 0x000c:
2248 case 0x0015: return lex_Ra;
2249 };
2250 }
2251
2252 static int sinhala_lex(WCHAR c)
2253 {
2254 switch (c)
2255 {
2256 case 0x0DDA:
2257 case 0x0DDD:
2258 case 0x0DDC:
2259 case 0x0DDE: return lex_Matra_post;
2260 default:
2261 return unicode_lex(c);
2262 }
2263 }
2264
2265 static const VowelComponents Sinhala_vowels[] = {
2266 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2267 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2268 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2269 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2270 {0x0000, {0x0000,0x0000,0x0}}};
2271
2272 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2273 {
2274 int cCount = cChars;
2275 int i;
2276 WCHAR *input;
2277 IndicSyllable *syllables = NULL;
2278 int syllable_count = 0;
2279
2280 if (*pcGlyphs != cChars)
2281 {
2282 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2283 return;
2284 }
2285
2286 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2287
2288 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2289
2290 /* Step 1: Decompose multi part vowels */
2291 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2292
2293 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2294
2295 /* Step 2: Reorder within Syllables */
2296 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2297 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2298
2299 /* Step 3: Strip dangling joiners */
2300 for (i = 0; i < cCount; i++)
2301 {
2302 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2303 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2304 input[i] = 0x0020;
2305 }
2306
2307 /* Step 4: Base Form application to syllables */
2308 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2309 *pcGlyphs = cCount;
2310 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2311
2312 HeapFree(GetProcessHeap(),0,input);
2313 HeapFree(GetProcessHeap(),0,syllables);
2314 }
2315
2316 static int devanagari_lex(WCHAR c)
2317 {
2318 switch (c)
2319 {
2320 case 0x0930: return lex_Ra;
2321 default:
2322 return unicode_lex(c);
2323 }
2324 }
2325
2326 static const ConsonantComponents Devanagari_consonants[] ={
2327 {{0x0928, 0x093C, 0x00000}, 0x0929},
2328 {{0x0930, 0x093C, 0x00000}, 0x0931},
2329 {{0x0933, 0x093C, 0x00000}, 0x0934},
2330 {{0x0915, 0x093C, 0x00000}, 0x0958},
2331 {{0x0916, 0x093C, 0x00000}, 0x0959},
2332 {{0x0917, 0x093C, 0x00000}, 0x095A},
2333 {{0x091C, 0x093C, 0x00000}, 0x095B},
2334 {{0x0921, 0x093C, 0x00000}, 0x095C},
2335 {{0x0922, 0x093C, 0x00000}, 0x095D},
2336 {{0x092B, 0x093C, 0x00000}, 0x095E},
2337 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2338
2339 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2340 {
2341 int cCount = cChars;
2342 WCHAR *input;
2343 IndicSyllable *syllables = NULL;
2344 int syllable_count = 0;
2345 BOOL modern = get_GSUB_Indic2(psa, psc);
2346
2347 if (*pcGlyphs != cChars)
2348 {
2349 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2350 return;
2351 }
2352
2353 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2354 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2355
2356 /* Step 1: Compose Consonant and Nukta */
2357 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2358 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2359
2360 /* Step 2: Reorder within Syllables */
2361 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2362 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2363 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2364 *pcGlyphs = cCount;
2365
2366 /* Step 3: Base Form application to syllables */
2367 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2368
2369 HeapFree(GetProcessHeap(),0,input);
2370 HeapFree(GetProcessHeap(),0,syllables);
2371 }
2372
2373 static int bengali_lex(WCHAR c)
2374 {
2375 switch (c)
2376 {
2377 case 0x09B0: return lex_Ra;
2378 default:
2379 return unicode_lex(c);
2380 }
2381 }
2382
2383 static const VowelComponents Bengali_vowels[] = {
2384 {0x09CB, {0x09C7,0x09BE,0x0000}},
2385 {0x09CC, {0x09C7,0x09D7,0x0000}},
2386 {0x0000, {0x0000,0x0000,0x0000}}};
2387
2388 static const ConsonantComponents Bengali_consonants[] = {
2389 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2390 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2391 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2392 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2393 {{0x0000,0x0000,0x0000}, 0x0000}};
2394
2395 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2396 {
2397 int cCount = cChars;
2398 WCHAR *input;
2399 IndicSyllable *syllables = NULL;
2400 int syllable_count = 0;
2401 BOOL modern = get_GSUB_Indic2(psa, psc);
2402
2403 if (*pcGlyphs != cChars)
2404 {
2405 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2406 return;
2407 }
2408
2409 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2410 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2411
2412 /* Step 1: Decompose Vowels and Compose Consonants */
2413 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2414 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2415 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2416
2417 /* Step 2: Reorder within Syllables */
2418 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2419 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2420 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2421 *pcGlyphs = cCount;
2422
2423 /* Step 3: Initial form is only applied to the beginning of words */
2424 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2425 {
2426 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2427 {
2428 int index = cCount;
2429 int gCount = 1;
2430 if (index > 0) index++;
2431
2432 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2433 }
2434 }
2435
2436 /* Step 4: Base Form application to syllables */
2437 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2438
2439 HeapFree(GetProcessHeap(),0,input);
2440 HeapFree(GetProcessHeap(),0,syllables);
2441 }
2442
2443 static int gurmukhi_lex(WCHAR c)
2444 {
2445 if (c == 0x0A71)
2446 return lex_Modifier;
2447 else
2448 return unicode_lex(c);
2449 }
2450
2451 static const ConsonantComponents Gurmukhi_consonants[] = {
2452 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2453 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2454 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2455 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2456 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2457 {{0x0000,0x0000,0x0000}, 0x0000}};
2458
2459 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2460 {
2461 int cCount = cChars;
2462 WCHAR *input;
2463 IndicSyllable *syllables = NULL;
2464 int syllable_count = 0;
2465 BOOL modern = get_GSUB_Indic2(psa, psc);
2466
2467 if (*pcGlyphs != cChars)
2468 {
2469 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2470 return;
2471 }
2472
2473 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2474 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2475
2476 /* Step 1: Compose Consonants */
2477 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2478 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2479
2480 /* Step 2: Reorder within Syllables */
2481 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2482 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2483 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2484 *pcGlyphs = cCount;
2485
2486 /* Step 3: Base Form application to syllables */
2487 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2488
2489 HeapFree(GetProcessHeap(),0,input);
2490 HeapFree(GetProcessHeap(),0,syllables);
2491 }
2492
2493 static int gujarati_lex(WCHAR c)
2494 {
2495 switch (c)
2496 {
2497 case 0x0AB0: return lex_Ra;
2498 default:
2499 return unicode_lex(c);
2500 }
2501 }
2502
2503 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2504 {
2505 int cCount = cChars;
2506 WCHAR *input;
2507 IndicSyllable *syllables = NULL;
2508 int syllable_count = 0;
2509 BOOL modern = get_GSUB_Indic2(psa, psc);
2510
2511 if (*pcGlyphs != cChars)
2512 {
2513 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2514 return;
2515 }
2516
2517 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2518 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2519
2520 /* Step 1: Reorder within Syllables */
2521 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2522 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2523 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2524 *pcGlyphs = cCount;
2525
2526 /* Step 2: Base Form application to syllables */
2527 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2528
2529 HeapFree(GetProcessHeap(),0,input);
2530 HeapFree(GetProcessHeap(),0,syllables);
2531 }
2532
2533 static int oriya_lex(WCHAR c)
2534 {
2535 switch (c)
2536 {
2537 case 0x0B30: return lex_Ra;
2538 default:
2539 return unicode_lex(c);
2540 }
2541 }
2542
2543 static const VowelComponents Oriya_vowels[] = {
2544 {0x0B48, {0x0B47,0x0B56,0x0000}},
2545 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2546 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2547 {0x0000, {0x0000,0x0000,0x0000}}};
2548
2549 static const ConsonantComponents Oriya_consonants[] = {
2550 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2551 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2552 {{0x0000,0x0000,0x0000}, 0x0000}};
2553
2554 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2555 {
2556 int cCount = cChars;
2557 WCHAR *input;
2558 IndicSyllable *syllables = NULL;
2559 int syllable_count = 0;
2560 BOOL modern = get_GSUB_Indic2(psa, psc);
2561
2562 if (*pcGlyphs != cChars)
2563 {
2564 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2565 return;
2566 }
2567
2568 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2569 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2570
2571 /* Step 1: Decompose Vowels and Compose Consonants */
2572 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2573 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2574 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2575
2576 /* Step 2: Reorder within Syllables */
2577 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2578 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2579 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2580 *pcGlyphs = cCount;
2581
2582 /* Step 3: Base Form application to syllables */
2583 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2584
2585 HeapFree(GetProcessHeap(),0,input);
2586 HeapFree(GetProcessHeap(),0,syllables);
2587 }
2588
2589 static int tamil_lex(WCHAR c)
2590 {
2591 return unicode_lex(c);
2592 }
2593
2594 static const VowelComponents Tamil_vowels[] = {
2595 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2596 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2597 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2598 {0x0000, {0x0000,0x0000,0x0000}}};
2599
2600 static const ConsonantComponents Tamil_consonants[] = {
2601 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2602 {{0x0000,0x0000,0x0000}, 0x0000}};
2603
2604 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2605 {
2606 int cCount = cChars;
2607 WCHAR *input;
2608 IndicSyllable *syllables = NULL;
2609 int syllable_count = 0;
2610 BOOL modern = get_GSUB_Indic2(psa, psc);
2611
2612 if (*pcGlyphs != cChars)
2613 {
2614 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2615 return;
2616 }
2617
2618 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2619 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2620
2621 /* Step 1: Decompose Vowels and Compose Consonants */
2622 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2623 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2624 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2625
2626 /* Step 2: Reorder within Syllables */
2627 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2628 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2629 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2630 *pcGlyphs = cCount;
2631
2632 /* Step 3: Base Form application to syllables */
2633 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2634
2635 HeapFree(GetProcessHeap(),0,input);
2636 HeapFree(GetProcessHeap(),0,syllables);
2637 }
2638
2639 static int telugu_lex(WCHAR c)
2640 {
2641 switch (c)
2642 {
2643 case 0x0C43:
2644 case 0x0C44: return lex_Modifier;
2645 default:
2646 return unicode_lex(c);
2647 }
2648 }
2649
2650 static const VowelComponents Telugu_vowels[] = {
2651 {0x0C48, {0x0C46,0x0C56,0x0000}},
2652 {0x0000, {0x0000,0x0000,0x0000}}};
2653
2654 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2655 {
2656 int cCount = cChars;
2657 WCHAR *input;
2658 IndicSyllable *syllables = NULL;
2659 int syllable_count = 0;
2660 BOOL modern = get_GSUB_Indic2(psa, psc);
2661
2662 if (*pcGlyphs != cChars)
2663 {
2664 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2665 return;
2666 }
2667
2668 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2669 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2670
2671 /* Step 1: Decompose Vowels */
2672 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2673 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2674
2675 /* Step 2: Reorder within Syllables */
2676 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2677 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2678 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2679 *pcGlyphs = cCount;
2680
2681 /* Step 3: Base Form application to syllables */
2682 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2683
2684 HeapFree(GetProcessHeap(),0,input);
2685 HeapFree(GetProcessHeap(),0,syllables);
2686 }
2687
2688 static int kannada_lex(WCHAR c)
2689 {
2690 switch (c)
2691 {
2692 case 0x0CB0: return lex_Ra;
2693 default:
2694 return unicode_lex(c);
2695 }
2696 }
2697
2698 static const VowelComponents Kannada_vowels[] = {
2699 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2700 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2701 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2702 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2703 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2704 {0x0000, {0x0000,0x0000,0x0000}}};
2705
2706 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2707 {
2708 int cCount = cChars;
2709 WCHAR *input;
2710 IndicSyllable *syllables = NULL;
2711 int syllable_count = 0;
2712 BOOL modern = get_GSUB_Indic2(psa, psc);
2713
2714 if (*pcGlyphs != cChars)
2715 {
2716 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2717 return;
2718 }
2719
2720 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2721 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2722
2723 /* Step 1: Decompose Vowels */
2724 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2725 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2726
2727 /* Step 2: Reorder within Syllables */
2728 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2729 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2730 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2731 *pcGlyphs = cCount;
2732
2733 /* Step 3: Base Form application to syllables */
2734 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2735
2736 HeapFree(GetProcessHeap(),0,input);
2737 HeapFree(GetProcessHeap(),0,syllables);
2738 }
2739
2740 static int malayalam_lex(WCHAR c)
2741 {
2742 return unicode_lex(c);
2743 }
2744
2745 static const VowelComponents Malayalam_vowels[] = {
2746 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2747 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2748 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2749 {0x0000, {0x0000,0x0000,0x0000}}};
2750
2751 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2752 {
2753 int cCount = cChars;
2754 WCHAR *input;
2755 IndicSyllable *syllables = NULL;
2756 int syllable_count = 0;
2757 BOOL modern = get_GSUB_Indic2(psa, psc);
2758
2759 if (*pcGlyphs != cChars)
2760 {
2761 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2762 return;
2763 }
2764
2765 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2766 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2767
2768 /* Step 1: Decompose Vowels */
2769 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2770 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2771
2772 /* Step 2: Reorder within Syllables */
2773 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2774 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2775 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2776 *pcGlyphs = cCount;
2777
2778 /* Step 3: Base Form application to syllables */
2779 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2780
2781 HeapFree(GetProcessHeap(),0,input);
2782 HeapFree(GetProcessHeap(),0,syllables);
2783 }
2784
2785 static int khmer_lex(WCHAR c)
2786 {
2787 return unicode_lex(c);
2788 }
2789
2790 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2791 {
2792 int cCount = cChars;
2793 WCHAR *input;
2794 IndicSyllable *syllables = NULL;
2795 int syllable_count = 0;
2796
2797 if (*pcGlyphs != cChars)
2798 {
2799 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2800 return;
2801 }
2802
2803 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2804 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2805
2806 /* Step 1: Reorder within Syllables */
2807 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2808 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2809 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2810 *pcGlyphs = cCount;
2811
2812 /* Step 2: Base Form application to syllables */
2813 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2814
2815 HeapFree(GetProcessHeap(),0,input);
2816 HeapFree(GetProcessHeap(),0,syllables);
2817 }
2818
2819 static inline BOOL mongolian_wordbreak(WCHAR chr)
2820 {
2821 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2822 }
2823
2824 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2825 {
2826 INT *context_shape;
2827 INT dirL;
2828 int i;
2829 int char_index;
2830 int glyph_index;
2831
2832 if (*pcGlyphs != cChars)
2833 {
2834 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2835 return;
2836 }
2837
2838 if (!psa->fLogicalOrder && psa->fRTL)
2839 dirL = -1;
2840 else
2841 dirL = 1;
2842
2843 if (!psc->GSUB_Table)
2844 return;
2845
2846 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2847
2848 for (i = 0; i < cChars; i++)
2849 {
2850 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2851 {
2852 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2853 context_shape[i] = Xn;
2854 else
2855 context_shape[i] = Xl;
2856 }
2857 else
2858 {
2859 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2860 context_shape[i] = Xr;
2861 else
2862 context_shape[i] = Xm;
2863 }
2864 }
2865
2866 /* Contextual Shaping */
2867 if (dirL > 0)
2868 char_index = glyph_index = 0;
2869 else
2870 char_index = glyph_index = cChars-1;
2871
2872 while(char_index < cChars && char_index >= 0)
2873 {
2874 INT nextIndex;
2875 INT prevCount = *pcGlyphs;
2876 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2877
2878 if (nextIndex > GSUB_E_NOGLYPH)
2879 {
2880 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2881 glyph_index = nextIndex;
2882 char_index += dirL;
2883 }
2884 else
2885 {
2886 char_index += dirL;
2887 glyph_index += dirL;
2888 }
2889 }
2890
2891 HeapFree(GetProcessHeap(),0,context_shape);
2892 }
2893
2894 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)
2895 {
2896 int i,k;
2897
2898 for (i = 0; i < cGlyphs; i++)
2899 {
2900 int char_index[20];
2901 int char_count = 0;
2902
2903 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2904 if (k>=0)
2905 {
2906 for (; k < cChars && pwLogClust[k] == i; k++)
2907 char_index[char_count++] = k;
2908 }
2909
2910 if (char_count == 0)
2911 continue;
2912
2913 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2914 {
2915 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2916 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2917 }
2918 else
2919 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2920 }
2921
2922 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2923 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2924 }
2925
2926 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 )
2927 {
2928 int i;
2929
2930 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2931
2932 for (i = 0; i < cGlyphs; i++)
2933 if (pGlyphProp[i].sva.fZeroWidth)
2934 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2935 }
2936
2937 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 )
2938 {
2939 int i;
2940 for (i = 0; i < cGlyphs; i++)
2941 {
2942 pGlyphProp[i].sva.fClusterStart = 1;
2943 pGlyphProp[i].sva.fDiacritic = 0;
2944 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2945
2946 if (pwGlyphs[i] == psc->sfp.wgDefault)
2947 pGlyphProp[i].sva.fZeroWidth = 0;
2948 else
2949 pGlyphProp[i].sva.fZeroWidth = 1;
2950 }
2951 }
2952
2953 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 )
2954 {
2955 int i,k;
2956 int initGlyph, finaGlyph;
2957 INT dirR, dirL;
2958 BYTE *spaces;
2959
2960 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2961 memset(spaces,0,cGlyphs);
2962
2963 if (!psa->fLogicalOrder && psa->fRTL)
2964 {
2965 initGlyph = cGlyphs-1;
2966 finaGlyph = 0;
2967 dirR = 1;
2968 dirL = -1;
2969 }
2970 else
2971 {
2972 initGlyph = 0;
2973 finaGlyph = cGlyphs-1;
2974 dirR = -1;
2975 dirL = 1;
2976 }
2977
2978 for (i = 0; i < cGlyphs; i++)
2979 {
2980 for (k = 0; k < cChars; k++)
2981 if (pwLogClust[k] == i)
2982 {
2983 if (pwcChars[k] == 0x0020)
2984 spaces[i] = 1;
2985 }
2986 }
2987
2988 for (i = 0; i < cGlyphs; i++)
2989 {
2990 int char_index[20];
2991 int char_count = 0;
2992 BOOL isInit, isFinal;
2993
2994 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2995 if (k>=0)
2996 {
2997 for (; k < cChars && pwLogClust[k] == i; k++)
2998 char_index[char_count++] = k;
2999 }
3000
3001 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3002 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3003
3004 if (char_count == 0)
3005 continue;
3006
3007 if (char_count == 1)
3008 {
3009 if (pwcChars[char_index[0]] == 0x0020) /* space */
3010 {
3011 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3012 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3013 }
3014 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3015 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3016 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3017 {
3018 if (!isInit && !isFinal)
3019 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3020 else if (isInit)
3021 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3022 else
3023 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3024 }
3025 else if (!isInit)
3026 {
3027 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3029 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3030 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3031 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3032 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3033 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3034 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3035 else
3036 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3037 }
3038 else if (!isInit && !isFinal)
3039 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3040 else
3041 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3042 }
3043 else if (char_count == 2)
3044 {
3045 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3046 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3047 else if (!isInit)
3048 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3049 else
3050 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3051 }
3052 else if (!isInit && !isFinal)
3053 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3054 else
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3056 }
3057
3058 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3059 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3060 HeapFree(GetProcessHeap(),0,spaces);
3061 }
3062
3063 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 )
3064 {
3065 int i,k;
3066
3067 for (i = 0; i < cGlyphs; i++)
3068 {
3069 int char_index[20];
3070 int char_count = 0;
3071
3072 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3073 if (k>=0)
3074 {
3075 for (; k < cChars && pwLogClust[k] == i; k++)
3076 char_index[char_count++] = k;
3077 }
3078
3079 if (char_count == 0)
3080 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3081 else
3082 {
3083 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3084 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3085 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3086 }
3087 }
3088
3089 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3090 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3091 }
3092
3093 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 )
3094 {
3095 int i;
3096 int finaGlyph;
3097 INT dirL;
3098
3099 if (!p