usp10: Add GPOS features to scripts as defined by VOLT.
[wine.git] / dlls / usp10 / shape.c
blob1ef6039cd0d3f0b87d2ebe10e56e9155380da973
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
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.
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.
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
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #define FIRST_ARABIC_CHAR 0x0600
39 #define LAST_ARABIC_CHAR 0x06ff
41 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
42 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
64 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
66 static void ShapeCharGlyphProp_Default( 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_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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
78 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 );
79 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 );
80 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 );
81 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 );
82 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 );
84 extern const unsigned short indic_syllabic_table[];
85 extern const unsigned short wine_shaping_table[];
86 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
88 enum joining_types {
89 jtU,
90 jtT,
91 jtR,
92 jtL,
93 jtD,
94 jtC
97 enum joined_forms {
98 Xn=0,
99 Xr,
102 /* Syriac Alaph */
103 Afj,
104 Afn,
108 typedef struct tagVowelComponents
110 WCHAR base;
111 WCHAR parts[3];
112 } VowelComponents;
114 typedef struct tagConsonantComponents
116 WCHAR parts[3];
117 WCHAR output;
118 } ConsonantComponents;
120 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
122 typedef int (*combining_lexical_function)(WCHAR c);
124 /* the orders of joined_forms and contextual_features need to line up */
125 static const char* contextual_features[] =
127 "isol",
128 "fina",
129 "init",
130 "medi",
131 /* Syriac Alaph */
132 "med2",
133 "fin2",
134 "fin3"
137 static OPENTYPE_FEATURE_RECORD standard_features[] =
139 { MS_MAKE_TAG('c','c','m','p'), 1},
140 { MS_MAKE_TAG('l','o','c','l'), 1},
143 static OPENTYPE_FEATURE_RECORD latin_features[] =
145 { MS_MAKE_TAG('l','i','g','a'), 1},
146 { MS_MAKE_TAG('c','l','i','g'), 1},
149 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
151 { MS_MAKE_TAG('k','e','r','n'), 1},
152 { MS_MAKE_TAG('m','a','r','k'), 1},
153 { MS_MAKE_TAG('m','k','m','k'), 1},
156 static OPENTYPE_FEATURE_RECORD arabic_features[] =
158 { MS_MAKE_TAG('r','l','i','g'), 1},
159 { MS_MAKE_TAG('c','a','l','t'), 1},
160 { MS_MAKE_TAG('l','i','g','a'), 1},
161 { MS_MAKE_TAG('d','l','i','g'), 1},
162 { MS_MAKE_TAG('c','s','w','h'), 1},
163 { MS_MAKE_TAG('m','s','e','t'), 1},
166 static const char* required_arabic_features[] =
168 "fina",
169 "init",
170 "medi",
171 "rlig",
172 NULL
175 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
177 { MS_MAKE_TAG('c','u','r','s'), 1},
178 { MS_MAKE_TAG('k','e','r','n'), 1},
179 { MS_MAKE_TAG('m','a','r','k'), 1},
180 { MS_MAKE_TAG('m','k','m','k'), 1},
183 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
185 { MS_MAKE_TAG('d','l','i','g'), 0},
188 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
190 { MS_MAKE_TAG('k','e','r','n'), 1},
191 { MS_MAKE_TAG('m','a','r','k'), 1},
194 static OPENTYPE_FEATURE_RECORD syriac_features[] =
196 { MS_MAKE_TAG('r','l','i','g'), 1},
197 { MS_MAKE_TAG('c','a','l','t'), 1},
198 { MS_MAKE_TAG('l','i','g','a'), 1},
199 { MS_MAKE_TAG('d','l','i','g'), 1},
202 static const char* required_syriac_features[] =
204 "fina",
205 "fin2",
206 "fin3",
207 "init",
208 "medi",
209 "med2",
210 "rlig",
211 NULL
214 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
216 { MS_MAKE_TAG('k','e','r','n'), 1},
217 { MS_MAKE_TAG('m','a','r','k'), 1},
218 { MS_MAKE_TAG('m','k','m','k'), 1},
221 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
223 /* Presentation forms */
224 { MS_MAKE_TAG('b','l','w','s'), 1},
225 { MS_MAKE_TAG('a','b','v','s'), 1},
226 { MS_MAKE_TAG('p','s','t','s'), 1},
229 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
231 { MS_MAKE_TAG('a','b','v','s'), 1},
232 { MS_MAKE_TAG('b','l','w','s'), 1},
235 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
237 { MS_MAKE_TAG('a','b','v','m'), 1},
238 { MS_MAKE_TAG('b','l','w','m'), 1},
241 static OPENTYPE_FEATURE_RECORD phags_features[] =
243 { MS_MAKE_TAG('a','b','v','s'), 1},
244 { MS_MAKE_TAG('b','l','w','s'), 1},
245 { MS_MAKE_TAG('c','a','l','t'), 1},
248 static OPENTYPE_FEATURE_RECORD thai_features[] =
250 { MS_MAKE_TAG('c','c','m','p'), 1},
253 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
255 { MS_MAKE_TAG('k','e','r','n'), 1},
256 { MS_MAKE_TAG('m','a','r','k'), 1},
257 { MS_MAKE_TAG('m','k','m','k'), 1},
260 static const char* required_lao_features[] =
262 "ccmp",
263 NULL
266 static const char* required_devanagari_features[] =
268 "nukt",
269 "akhn",
270 "rphf",
271 "blwf",
272 "half",
273 "vatu",
274 "pres",
275 "abvs",
276 "blws",
277 "psts",
278 "haln",
279 NULL
282 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
284 { MS_MAKE_TAG('p','r','e','s'), 1},
285 { MS_MAKE_TAG('a','b','v','s'), 1},
286 { MS_MAKE_TAG('b','l','w','s'), 1},
287 { MS_MAKE_TAG('p','s','t','s'), 1},
288 { MS_MAKE_TAG('h','a','l','n'), 1},
289 { MS_MAKE_TAG('c','a','l','t'), 1},
292 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
294 { MS_MAKE_TAG('k','e','r','n'), 1},
295 { MS_MAKE_TAG('d','i','s','t'), 1},
296 { MS_MAKE_TAG('a','b','v','m'), 1},
297 { MS_MAKE_TAG('b','l','w','m'), 1},
300 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
302 { MS_MAKE_TAG('l','i','g','a'), 1},
303 { MS_MAKE_TAG('c','l','i','g'), 1},
306 static const char* required_bengali_features[] =
308 "nukt",
309 "akhn",
310 "rphf",
311 "blwf",
312 "half",
313 "vatu",
314 "pstf",
315 "init",
316 "abvs",
317 "blws",
318 "psts",
319 "haln",
320 NULL
323 static const char* required_gurmukhi_features[] =
325 "nukt",
326 "akhn",
327 "rphf",
328 "blwf",
329 "half",
330 "pstf",
331 "vatu",
332 "cjct",
333 "pres",
334 "abvs",
335 "blws",
336 "psts",
337 "haln",
338 "calt",
339 NULL
342 static const char* required_oriya_features[] =
344 "nukt",
345 "akhn",
346 "rphf",
347 "blwf",
348 "pstf",
349 "cjct",
350 "pres",
351 "abvs",
352 "blws",
353 "psts",
354 "haln",
355 "calt",
356 NULL
359 static const char* required_tamil_features[] =
361 "nukt",
362 "akhn",
363 "rphf",
364 "pref",
365 "half",
366 "pres",
367 "abvs",
368 "blws",
369 "psts",
370 "haln",
371 "calt",
372 NULL
375 static const char* required_telugu_features[] =
377 "nukt",
378 "akhn",
379 "rphf",
380 "pref",
381 "half",
382 "pstf",
383 "cjct",
384 "pres",
385 "abvs",
386 "blws",
387 "psts",
388 "haln",
389 "calt",
390 NULL
393 static OPENTYPE_FEATURE_RECORD khmer_features[] =
395 { MS_MAKE_TAG('p','r','e','s'), 1},
396 { MS_MAKE_TAG('b','l','w','s'), 1},
397 { MS_MAKE_TAG('a','b','v','s'), 1},
398 { MS_MAKE_TAG('p','s','t','s'), 1},
399 { MS_MAKE_TAG('c','l','i','g'), 1},
402 static const char* required_khmer_features[] =
404 "pref",
405 "blwf",
406 "abvf",
407 "pstf",
408 "pres",
409 "blws",
410 "abvs",
411 "psts",
412 "clig",
413 NULL
416 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
418 { MS_MAKE_TAG('d','i','s','t'), 1},
419 { MS_MAKE_TAG('b','l','w','m'), 1},
420 { MS_MAKE_TAG('a','b','v','m'), 1},
421 { MS_MAKE_TAG('m','k','m','k'), 1},
424 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
426 { MS_MAKE_TAG('c','c','m','p'), 1},
427 { MS_MAKE_TAG('l','o','c','l'), 1},
428 { MS_MAKE_TAG('c','a','l','t'), 1},
429 { MS_MAKE_TAG('l','i','g','a'), 1},
432 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
434 { MS_MAKE_TAG('c','c','m','p'), 1},
435 { MS_MAKE_TAG('l','o','c','l'), 1},
436 { MS_MAKE_TAG('c','a','l','t'), 1},
437 { MS_MAKE_TAG('r','l','i','g'), 1},
440 typedef struct ScriptShapeDataTag {
441 TEXTRANGE_PROPERTIES defaultTextRange;
442 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
443 const char** requiredFeatures;
444 OPENTYPE_TAG newOtTag;
445 ContextualShapingProc contextProc;
446 ShapeCharGlyphPropProc charGlyphPropProc;
447 } ScriptShapeData;
449 /* in order of scripts */
450 static const ScriptShapeData ShapingData[] =
452 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
453 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
454 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
455 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
456 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
457 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
458 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
459 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
460 {{ hebrew_features, 1}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
461 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
462 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
463 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
464 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
465 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
466 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
467 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
468 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
469 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
470 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
471 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
472 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
473 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
474 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
475 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
476 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
477 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
478 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
479 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
480 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
481 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
482 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
483 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
496 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
497 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
498 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
499 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
500 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
501 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
502 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
503 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
504 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
505 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
506 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
511 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
512 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
513 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
515 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
516 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
522 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
523 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
524 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
526 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
527 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
528 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
529 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
530 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
531 {{ hebrew_features, 1}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
532 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
533 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
536 extern scriptData scriptInformation[];
538 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
540 int i;
541 int out_index = GSUB_E_NOGLYPH;
543 TRACE("%i lookups\n", feature->lookup_count);
544 for (i = 0; i < feature->lookup_count; i++)
546 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
547 if (out_index != GSUB_E_NOGLYPH)
548 break;
550 if (out_index == GSUB_E_NOGLYPH)
551 TRACE("lookups found no glyphs\n");
552 else
554 int out2;
555 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
556 if (out2!=GSUB_E_NOGLYPH)
557 out_index = out2;
559 return out_index;
562 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
564 UINT charset;
566 if (psc->userScript != 0)
568 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
569 return ShapingData[psa->eScript].newOtTag;
570 else
571 return psc->userScript;
574 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
575 return ShapingData[psa->eScript].newOtTag;
577 if (scriptInformation[psa->eScript].scriptTag)
578 return scriptInformation[psa->eScript].scriptTag;
581 * fall back to the font charset
583 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
584 switch (charset)
586 case ANSI_CHARSET:
587 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
588 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
589 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
590 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
591 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
592 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
593 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
594 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
595 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
596 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
597 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
598 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
599 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
600 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
601 default: return MS_MAKE_TAG('l','a','t','n');
605 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
607 LoadedFeature *feature = NULL;
609 if (psc->GSUB_Table || psc->GPOS_Table)
611 int attempt = 2;
612 OPENTYPE_TAG tags;
613 OPENTYPE_TAG language;
614 OPENTYPE_TAG script;
615 int cTags;
619 script = get_opentype_script(hdc,psa,psc,(attempt==2));
620 if (psc->userLang != 0)
621 language = psc->userLang;
622 else
623 language = MS_MAKE_TAG('d','f','l','t');
624 attempt--;
626 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
628 } while(attempt && !feature);
630 /* try in the default (latin) table */
631 if (!feature)
632 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]), 1, &tags, &cTags, &feature);
635 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
636 return feature;
639 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)
641 LoadedFeature *feature;
643 feature = load_OT_feature(hdc, psa, psc, feat);
644 if (!feature)
645 return GSUB_E_NOFEATURE;
647 TRACE("applying feature %s\n",feat);
648 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
651 static VOID *load_gsub_table(HDC hdc)
653 VOID* GSUB_Table = NULL;
654 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
655 if (length != GDI_ERROR)
657 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
658 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
659 TRACE("Loaded GSUB table of %i bytes\n",length);
661 return GSUB_Table;
664 static VOID *load_gpos_table(HDC hdc)
666 VOID* GPOS_Table = NULL;
667 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
668 if (length != GDI_ERROR)
670 GPOS_Table = HeapAlloc(GetProcessHeap(),0,length);
671 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
672 TRACE("Loaded GPOS table of %i bytes\n",length);
674 return GPOS_Table;
677 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
679 if (!psc->GSUB_Table)
680 psc->GSUB_Table = load_gsub_table(hdc);
681 if (!psc->GPOS_Table)
682 psc->GPOS_Table = load_gpos_table(hdc);
685 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)
687 WORD *glyphs;
688 INT glyph_count = count;
689 INT rc;
691 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
692 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
693 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
694 if (rc > GSUB_E_NOGLYPH)
695 rc = count - glyph_count;
696 else
697 rc = 0;
699 HeapFree(GetProcessHeap(),0,glyphs);
700 return rc;
703 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
705 int i;
707 for (i = 0; i < cGlyphs; i++)
709 if (!pGlyphProp[i].sva.fClusterStart)
711 int j;
712 for (j = 0; j < cChars; j++)
714 if (pwLogClust[j] == i)
716 int k = j;
717 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
718 k-=1;
719 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
720 pwLogClust[j] = pwLogClust[k];
727 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
729 if (changeCount == 0)
730 return;
731 else
733 int i;
734 int target_glyph = nextIndex - write_dir;
735 int seeking_glyph;
736 int target_index = -1;
737 int replacing_glyph = -1;
738 int changed = 0;
739 int top_logclust = 0;
741 if (changeCount > 0)
743 if (write_dir > 0)
744 target_glyph = nextIndex - changeCount;
745 else
746 target_glyph = nextIndex + (changeCount + 1);
749 seeking_glyph = target_glyph;
750 for (i = 0; i < chars; i++)
751 if (pwLogClust[i] > top_logclust)
752 top_logclust = pwLogClust[i];
754 do {
755 if (write_dir > 0)
756 for (i = 0; i < chars; i++)
758 if (pwLogClust[i] == seeking_glyph)
760 target_index = i;
761 break;
764 else
765 for (i = chars - 1; i >= 0; i--)
767 if (pwLogClust[i] == seeking_glyph)
769 target_index = i;
770 break;
773 if (target_index == -1)
774 seeking_glyph ++;
776 while (target_index == -1 && seeking_glyph <= top_logclust);
778 if (target_index == -1)
780 ERR("Unable to find target glyph\n");
781 return;
784 if (changeCount < 0)
786 /* merge glyphs */
787 for(i = target_index; i < chars && i >= 0; i+=write_dir)
789 if (pwLogClust[i] == target_glyph)
790 continue;
791 if(pwLogClust[i] == replacing_glyph)
792 pwLogClust[i] = target_glyph;
793 else
795 changed--;
796 if (changed >= changeCount)
798 replacing_glyph = pwLogClust[i];
799 pwLogClust[i] = target_glyph;
801 else
802 break;
806 /* renumber trailing indexes*/
807 for(i = target_index; i < chars && i >= 0; i+=write_dir)
809 if (pwLogClust[i] != target_glyph)
810 pwLogClust[i] += changeCount;
813 else
815 for(i = target_index; i < chars && i >= 0; i+=write_dir)
816 pwLogClust[i] += changeCount;
821 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 )
823 if (psc->GSUB_Table)
825 LoadedFeature *feature;
826 int lookup_index;
828 feature = load_OT_feature(hdc, psa, psc, feat);
829 if (!feature)
830 return GSUB_E_NOFEATURE;
832 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
833 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
835 int i;
837 if (write_dir > 0)
838 i = 0;
839 else
840 i = *pcGlyphs-1;
841 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
842 while(i < *pcGlyphs && i >= 0)
844 INT nextIndex;
845 INT prevCount = *pcGlyphs;
847 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
848 if (*pcGlyphs != prevCount)
850 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
851 i = nextIndex;
853 else
854 i+=write_dir;
857 return *pcGlyphs;
859 return GSUB_E_NOFEATURE;
862 static VOID GPOS_apply_feature(LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, INT* piAdvance, LPCVOID header, LoadedFeature *feature, const WORD *glyphs, INT write_dir, INT glyph_count, GOFFSET *pGoffset)
864 int i;
866 TRACE("%i lookups\n", feature->lookup_count);
867 for (i = 0; i < feature->lookup_count; i++)
869 int j;
870 for (j = 0; j < glyph_count; )
871 j = OpenType_apply_GPOS_lookup(lpotm, lplogfont, piAdvance, header, feature->lookups[i], glyphs, j, write_dir, glyph_count, pGoffset);
875 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
877 OPENTYPE_TAG tag;
878 HRESULT hr;
879 int count = 0;
881 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
883 return(SUCCEEDED(hr));
886 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
888 int i;
889 for (i = *pcGlyphs; i>=index; i--)
890 pwGlyphs[i+1] = pwGlyphs[i];
891 pwGlyphs[index] = glyph;
892 *pcGlyphs = *pcGlyphs+1;
893 if (write_dir < 0)
894 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
895 else
896 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
899 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)
901 CHAR *context_type;
902 int i,g;
903 WCHAR invalid = 0x25cc;
904 WORD invalid_glyph;
906 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
908 /* Mark invalid combinations */
909 for (i = 0; i < cChars; i++)
910 context_type[i] = lex(pwcChars[i]);
912 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
913 for (i = 1, g=1; i < cChars; i++, g++)
915 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
917 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
918 g++;
922 HeapFree(GetProcessHeap(),0,context_type);
925 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
927 if (i + delta < 0)
928 return 0;
929 if ( i+ delta >= cchLen)
930 return 0;
932 i += delta;
934 return chars[i];
937 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
939 if (i + delta < 0)
941 if (psa->fLinkBefore)
942 return jtR;
943 else
944 return jtU;
946 if ( i+ delta >= cchLen)
948 if (psa->fLinkAfter)
949 return jtL;
950 else
951 return jtU;
954 i += delta;
956 if (context_type[i] == jtT)
957 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
958 else
959 return context_type[i];
962 static inline BOOL right_join_causing(CHAR joining_type)
964 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
967 static inline BOOL left_join_causing(CHAR joining_type)
969 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
972 static inline BOOL word_break_causing(WCHAR chr)
974 /* we are working within a string of characters already guareented to
975 be within one script, Syriac, so we do not worry about any character
976 other than the space character outside of that range */
977 return (chr == 0 || chr == 0x20 );
980 static int combining_lexical_Arabic(WCHAR c)
982 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
984 switch(c)
986 case 0x064B:
987 case 0x064C:
988 case 0x064E:
989 case 0x064F:
990 case 0x0652:
991 case 0x0657:
992 case 0x0658:
993 case 0x06E1: return Arab_DIAC1;
994 case 0x064D:
995 case 0x0650:
996 case 0x0656: return Arab_DIAC2;
997 case 0x0651: return Arab_DIAC3;
998 case 0x0610:
999 case 0x0611:
1000 case 0x0612:
1001 case 0x0613:
1002 case 0x0614:
1003 case 0x0659:
1004 case 0x06D6:
1005 case 0x06DC:
1006 case 0x06DF:
1007 case 0x06E0:
1008 case 0x06E2:
1009 case 0x06E4:
1010 case 0x06E7:
1011 case 0x06E8:
1012 case 0x06EB:
1013 case 0x06EC: return Arab_DIAC4;
1014 case 0x06E3:
1015 case 0x06EA:
1016 case 0x06ED: return Arab_DIAC5;
1017 case 0x0670: return Arab_DIAC6;
1018 case 0x0653: return Arab_DIAC7;
1019 case 0x0655:
1020 case 0x0654: return Arab_DIAC8;
1021 default: return Arab_Norm;
1026 * ContextualShape_Arabic
1028 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1030 CHAR *context_type;
1031 INT *context_shape;
1032 INT dirR, dirL;
1033 int i;
1035 if (*pcGlyphs != cChars)
1037 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1038 return;
1041 if (!psa->fLogicalOrder && psa->fRTL)
1043 dirR = 1;
1044 dirL = -1;
1046 else
1048 dirR = -1;
1049 dirL = 1;
1052 load_ot_tables(hdc, psc);
1054 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1055 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1057 for (i = 0; i < cChars; i++)
1058 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1060 for (i = 0; i < cChars; i++)
1062 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1063 context_shape[i] = Xr;
1064 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1065 context_shape[i] = Xl;
1066 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)))
1067 context_shape[i] = Xm;
1068 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1069 context_shape[i] = Xr;
1070 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1071 context_shape[i] = Xl;
1072 else
1073 context_shape[i] = Xn;
1076 /* Contextual Shaping */
1077 i = 0;
1078 while(i < *pcGlyphs)
1080 BOOL shaped = FALSE;
1082 if (psc->GSUB_Table)
1084 INT nextIndex;
1085 INT prevCount = *pcGlyphs;
1086 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1087 if (nextIndex > GSUB_E_NOGLYPH)
1089 i = nextIndex;
1090 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1092 shaped = (nextIndex > GSUB_E_NOGLYPH);
1095 if (!shaped)
1097 if (context_shape[i] == Xn)
1099 WORD newGlyph = pwOutGlyphs[i];
1100 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1102 /* fall back to presentation form B */
1103 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1104 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1105 pwOutGlyphs[i] = newGlyph;
1108 i++;
1112 HeapFree(GetProcessHeap(),0,context_shape);
1113 HeapFree(GetProcessHeap(),0,context_type);
1115 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1118 static int combining_lexical_Hebrew(WCHAR c)
1120 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};
1122 switch(c)
1124 case 0x05B0:
1125 case 0x05B1:
1126 case 0x05B2:
1127 case 0x05B3:
1128 case 0x05B4:
1129 case 0x05B5:
1130 case 0x05B6:
1131 case 0x05BB: return Hebr_DIAC;
1132 case 0x0599:
1133 case 0x05A1:
1134 case 0x05A9:
1135 case 0x05AE: return Hebr_CANT1;
1136 case 0x0597:
1137 case 0x05A8:
1138 case 0x05AC: return Hebr_CANT2;
1139 case 0x0592:
1140 case 0x0593:
1141 case 0x0594:
1142 case 0x0595:
1143 case 0x05A7:
1144 case 0x05AB: return Hebr_CANT3;
1145 case 0x0598:
1146 case 0x059C:
1147 case 0x059E:
1148 case 0x059F: return Hebr_CANT4;
1149 case 0x059D:
1150 case 0x05A0: return Hebr_CANT5;
1151 case 0x059B:
1152 case 0x05A5: return Hebr_CANT6;
1153 case 0x0591:
1154 case 0x05A3:
1155 case 0x05A6: return Hebr_CANT7;
1156 case 0x0596:
1157 case 0x05A4:
1158 case 0x05AA: return Hebr_CANT8;
1159 case 0x059A:
1160 case 0x05AD: return Hebr_CANT9;
1161 case 0x05AF: return Hebr_CANT10;
1162 case 0x05BC: return Hebr_DAGESH;
1163 case 0x05C4: return Hebr_DOTABV;
1164 case 0x05B9: return Hebr_HOLAM;
1165 case 0x05BD: return Hebr_METEG;
1166 case 0x05B7: return Hebr_PATAH;
1167 case 0x05B8: return Hebr_QAMATS;
1168 case 0x05BF: return Hebr_RAFE;
1169 case 0x05C1:
1170 case 0x05C2: return Hebr_SHINSIN;
1171 default: return Hebr_Norm;
1175 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1177 INT dirL;
1179 if (*pcGlyphs != cChars)
1181 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1182 return;
1185 if (!psa->fLogicalOrder && psa->fRTL)
1186 dirL = -1;
1187 else
1188 dirL = 1;
1190 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1194 * ContextualShape_Syriac
1197 static int combining_lexical_Syriac(WCHAR c)
1199 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};
1201 switch(c)
1203 case 0x730:
1204 case 0x733:
1205 case 0x736:
1206 case 0x73A:
1207 case 0x73D: return Syriac_DIAC1;
1208 case 0x731:
1209 case 0x734:
1210 case 0x737:
1211 case 0x73B:
1212 case 0x73E: return Syriac_DIAC2;
1213 case 0x740:
1214 case 0x749:
1215 case 0x74A: return Syriac_DIAC3;
1216 case 0x732:
1217 case 0x735:
1218 case 0x73F: return Syriac_DIAC4;
1219 case 0x738:
1220 case 0x739:
1221 case 0x73C: return Syriac_DIAC5;
1222 case 0x741:
1223 case 0x30A: return Syriac_DIAC6;
1224 case 0x742:
1225 case 0x325: return Syriac_DIAC7;
1226 case 0x747:
1227 case 0x303: return Syriac_DIAC8;
1228 case 0x748:
1229 case 0x32D:
1230 case 0x32E:
1231 case 0x330:
1232 case 0x331: return Syriac_DIAC9;
1233 case 0x308: return Syriac_DIAC10;
1234 case 0x304: return Syriac_DIAC11;
1235 case 0x307: return Syriac_DIAC12;
1236 case 0x323: return Syriac_DIAC13;
1237 case 0x743: return Syriac_DIAC14;
1238 case 0x744: return Syriac_DIAC15;
1239 case 0x745: return Syriac_DIAC16;
1240 case 0x746: return Syriac_DIAC17;
1241 default: return Syriac_Norm;
1245 #define ALAPH 0x710
1246 #define DALATH 0x715
1247 #define RISH 0x72A
1249 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1251 CHAR *context_type;
1252 INT *context_shape;
1253 INT dirR, dirL;
1254 int i;
1256 if (*pcGlyphs != cChars)
1258 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1259 return;
1262 if (!psa->fLogicalOrder && psa->fRTL)
1264 dirR = 1;
1265 dirL = -1;
1267 else
1269 dirR = -1;
1270 dirL = 1;
1273 load_ot_tables(hdc, psc);
1275 if (!psc->GSUB_Table)
1276 return;
1278 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1279 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1281 for (i = 0; i < cChars; i++)
1282 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1284 for (i = 0; i < cChars; i++)
1286 if (pwcChars[i] == ALAPH)
1288 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1290 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1291 context_shape[i] = Afj;
1292 else if ( rchar != DALATH && rchar != RISH &&
1293 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1294 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1295 context_shape[i] = Afn;
1296 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1297 context_shape[i] = Afx;
1298 else
1299 context_shape[i] = Xn;
1301 else if (context_type[i] == jtR &&
1302 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1303 context_shape[i] = Xr;
1304 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1305 context_shape[i] = Xl;
1306 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)))
1307 context_shape[i] = Xm;
1308 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1309 context_shape[i] = Xr;
1310 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1311 context_shape[i] = Xl;
1312 else
1313 context_shape[i] = Xn;
1316 /* Contextual Shaping */
1317 i = 0;
1318 while(i < *pcGlyphs)
1320 INT nextIndex;
1321 INT prevCount = *pcGlyphs;
1322 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1323 if (nextIndex > GSUB_E_NOGLYPH)
1325 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1326 i = nextIndex;
1328 else
1329 i++;
1332 HeapFree(GetProcessHeap(),0,context_shape);
1333 HeapFree(GetProcessHeap(),0,context_type);
1335 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1338 static int combining_lexical_Thaana(WCHAR c)
1340 enum {Thaana_Norm=0, Thaana_FILI};
1342 switch(c)
1344 case 0x7A6:
1345 case 0x7A7:
1346 case 0x7A8:
1347 case 0x7A9:
1348 case 0x7AA:
1349 case 0x7AB:
1350 case 0x7AC:
1351 case 0x7AD:
1352 case 0x7AE:
1353 case 0x7AF: return Thaana_FILI;
1354 default: return Thaana_Norm;
1358 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1360 INT dirL;
1362 if (*pcGlyphs != cChars)
1364 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1365 return;
1368 if (!psa->fLogicalOrder && psa->fRTL)
1369 dirL = -1;
1370 else
1371 dirL = 1;
1373 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1377 * ContextualShape_Phags_pa
1380 #define phags_pa_CANDRABINDU 0xA873
1381 #define phags_pa_START 0xA840
1382 #define phags_pa_END 0xA87F
1384 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1386 INT *context_shape;
1387 INT dirR, dirL;
1388 int i;
1390 if (*pcGlyphs != cChars)
1392 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1393 return;
1396 if (!psa->fLogicalOrder && psa->fRTL)
1398 dirR = 1;
1399 dirL = -1;
1401 else
1403 dirR = -1;
1404 dirL = 1;
1407 load_ot_tables(hdc, psc);
1409 if (!psc->GSUB_Table)
1410 return;
1412 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1414 for (i = 0; i < cChars; i++)
1416 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1418 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1419 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1420 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1421 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1423 if (jrchar && jlchar)
1424 context_shape[i] = Xm;
1425 else if (jrchar)
1426 context_shape[i] = Xr;
1427 else if (jlchar)
1428 context_shape[i] = Xl;
1429 else
1430 context_shape[i] = Xn;
1432 else
1433 context_shape[i] = -1;
1436 /* Contextual Shaping */
1437 i = 0;
1438 while(i < *pcGlyphs)
1440 if (context_shape[i] >= 0)
1442 INT nextIndex;
1443 INT prevCount = *pcGlyphs;
1444 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1445 if (nextIndex > GSUB_E_NOGLYPH)
1447 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1448 i = nextIndex;
1450 else
1451 i++;
1453 else
1454 i++;
1457 HeapFree(GetProcessHeap(),0,context_shape);
1460 static int combining_lexical_Thai(WCHAR c)
1462 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1464 switch(c)
1466 case 0xE31:
1467 case 0xE34:
1468 case 0xE35:
1469 case 0xE36:
1470 case 0xE37: return Thai_ABOVE1;
1471 case 0xE47:
1472 case 0xE4D: return Thai_ABOVE2;
1473 case 0xE48:
1474 case 0xE49:
1475 case 0xE4A:
1476 case 0xE4B: return Thai_ABOVE3;
1477 case 0xE4C:
1478 case 0xE4E: return Thai_ABOVE4;
1479 case 0xE38:
1480 case 0xE39: return Thai_BELOW1;
1481 case 0xE3A: return Thai_BELOW2;
1482 case 0xE33: return Thai_AM;
1483 default: return Thai_Norm;
1487 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1489 INT dirL;
1491 if (*pcGlyphs != cChars)
1493 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1494 return;
1497 if (!psa->fLogicalOrder && psa->fRTL)
1498 dirL = -1;
1499 else
1500 dirL = 1;
1502 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1505 static int combining_lexical_Lao(WCHAR c)
1507 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1509 switch(c)
1511 case 0xEB1:
1512 case 0xEB4:
1513 case 0xEB5:
1514 case 0xEB6:
1515 case 0xEB7:
1516 case 0xEBB:
1517 case 0xECD: return Lao_ABOVE1;
1518 case 0xEC8:
1519 case 0xEC9:
1520 case 0xECA:
1521 case 0xECB:
1522 case 0xECC: return Lao_ABOVE2;
1523 case 0xEBC: return Lao_BELOW1;
1524 case 0xEB8:
1525 case 0xEB9: return Lao_BELOW2;
1526 case 0xEB3: return Lao_AM;
1527 default: return Lao_Norm;
1531 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1533 INT dirL;
1535 if (*pcGlyphs != cChars)
1537 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1538 return;
1541 if (!psa->fLogicalOrder && psa->fRTL)
1542 dirL = -1;
1543 else
1544 dirL = 1;
1546 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1549 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1551 int i;
1553 /* Replace */
1554 pwOutChars[cWalk] = replacements[0];
1555 cWalk=cWalk+1;
1557 /* Insert */
1558 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1560 int j;
1561 for (j = *pcChars; j > cWalk; j--)
1562 pwOutChars[j] = pwOutChars[j-1];
1563 *pcChars= *pcChars+1;
1564 pwOutChars[cWalk] = replacements[i];
1565 cWalk = cWalk+1;
1569 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1571 int i;
1572 int cWalk;
1574 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1576 for (i = 0; vowels[i].base != 0x0; i++)
1578 if (pwOutChars[cWalk] == vowels[i].base)
1580 int o = 0;
1581 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1582 if (vowels[i].parts[1]) { cWalk++; o++; }
1583 if (vowels[i].parts[2]) { cWalk++; o++; }
1584 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1585 break;
1591 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1593 int i;
1594 int offset = 0;
1595 int cWalk;
1597 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1599 for (i = 0; consonants[i].output!= 0x0; i++)
1601 int j;
1602 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1603 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1604 break;
1606 if (consonants[i].parts[j]==0x0) /* matched all */
1608 int k;
1609 j--;
1610 pwOutChars[cWalk] = consonants[i].output;
1611 for(k = cWalk+1; k < *pcChars - j; k++)
1612 pwOutChars[k] = pwOutChars[k+j];
1613 *pcChars = *pcChars - j;
1614 for (k = j ; k > 0; k--)
1615 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1616 offset += j;
1617 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1618 pwLogClust[k]--;
1619 break;
1622 cWalk++;
1626 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1628 if (s->ralf >= 0)
1630 int j;
1631 WORD Ra = pwChar[s->start];
1632 WORD H = pwChar[s->start+1];
1634 TRACE("Doing reorder of Ra to %i\n",s->base);
1635 for (j = s->start; j < s->base-1; j++)
1636 pwChar[j] = pwChar[j+2];
1637 pwChar[s->base-1] = Ra;
1638 pwChar[s->base] = H;
1640 s->ralf = s->base-1;
1641 s->base -= 2;
1645 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1647 if (s->ralf >= 0)
1649 int j,loc;
1650 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1651 WORD Ra = pwChar[s->start];
1652 WORD H = pwChar[s->start+1];
1653 for (loc = s->end; loc > stop; loc--)
1654 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1655 break;
1657 TRACE("Doing reorder of Ra to %i\n",loc);
1658 for (j = s->start; j < loc-1; j++)
1659 pwChar[j] = pwChar[j+2];
1660 pwChar[loc-1] = Ra;
1661 pwChar[loc] = H;
1663 s->ralf = loc-1;
1664 s->base -= 2;
1665 if (s->blwf >= 0) s->blwf -= 2;
1666 if (s->pref >= 0) s->pref -= 2;
1670 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1672 if (s->ralf >= 0)
1674 int j;
1675 WORD Ra = pwChar[s->start];
1676 WORD H = pwChar[s->start+1];
1678 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1679 for (j = s->start; j < s->end-1; j++)
1680 pwChar[j] = pwChar[j+2];
1681 pwChar[s->end-1] = Ra;
1682 pwChar[s->end] = H;
1684 s->ralf = s->end-1;
1685 s->base -= 2;
1686 if (s->blwf >= 0) s->blwf -= 2;
1687 if (s->pref >= 0) s->pref -= 2;
1691 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1693 int i;
1695 /* reorder Matras */
1696 if (s->end > s->base)
1698 for (i = 1; i <= s->end-s->base; i++)
1700 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1702 int j;
1703 WCHAR c = pwChar[s->base+i];
1704 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1705 for (j = s->base+i; j > s->base; j--)
1706 pwChar[j] = pwChar[j-1];
1707 pwChar[s->base] = c;
1709 if (s->ralf >= s->base) s->ralf++;
1710 if (s->blwf >= s->base) s->blwf++;
1711 if (s->pref >= s->base) s->pref++;
1712 s->base ++;
1718 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1720 int i;
1722 /* reorder Matras */
1723 if (s->end > s->base)
1725 for (i = 1; i <= s->end-s->base; i++)
1727 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1729 int j;
1730 WCHAR c = pwChar[s->base+i];
1731 TRACE("Doing reorder of %x to %i\n",c,s->start);
1732 for (j = s->base+i; j > s->start; j--)
1733 pwChar[j] = pwChar[j-1];
1734 pwChar[s->start] = c;
1736 if (s->ralf >= 0) s->ralf++;
1737 if (s->blwf >= 0) s->blwf++;
1738 if (s->pref >= 0) s->pref++;
1739 s->base ++;
1745 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1747 if (s->blwf >= 0 && g->blwf > g->base)
1749 int j,loc;
1750 int g_offset;
1751 for (loc = s->end; loc > s->blwf; loc--)
1752 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1753 break;
1755 g_offset = (loc - s->blwf) - 1;
1757 if (loc != s->blwf)
1759 WORD blwf = glyphs[g->blwf];
1760 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1761 /* do not care about the pwChar array anymore, just the glyphs */
1762 for (j = 0; j < g_offset; j++)
1763 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1764 glyphs[g->blwf + g_offset] = blwf;
1769 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1771 int i;
1773 /* reorder previously moved Matras to correct position*/
1774 for (i = s->start; i < s->base; i++)
1776 if (lexical(pwChar[i]) == lex_Matra_pre)
1778 int j;
1779 int g_start = g->start + i - s->start;
1780 if (g_start < g->base -1 )
1782 WCHAR og = glyphs[g_start];
1783 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1784 for (j = g_start; j < g->base-1; j++)
1785 glyphs[j] = glyphs[j+1];
1786 glyphs[g->base-1] = og;
1792 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1794 if (s->pref >= 0 && g->pref > g->base)
1796 int j;
1797 WCHAR og = glyphs[g->pref];
1798 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1799 for (j = g->pref; j > g->base; j--)
1800 glyphs[j] = glyphs[j-1];
1801 glyphs[g->base] = og;
1805 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1807 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1808 if (s->start == s->base && s->base == s->end) return;
1809 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1811 Reorder_Ra_follows_base(pwChar, s, lexical);
1812 Reorder_Matra_precede_base(pwChar, s, lexical);
1815 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1817 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1818 if (s->start == s->base && s->base == s->end) return;
1819 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1821 Reorder_Ra_follows_matra(pwChar, s, lexical);
1822 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1825 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1827 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1828 if (s->start == s->base && s->base == s->end) return;
1829 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1831 Reorder_Ra_follows_base(pwChar, s, lexical);
1832 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1835 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1837 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1838 if (s->start == s->base && s->base == s->end) return;
1839 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1841 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1842 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1845 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1847 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1848 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1849 if (s->start == s->base && s->base == s->end) return;
1850 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1852 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1855 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1857 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1858 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1859 if (s->start == s->base && s->base == s->end) return;
1860 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1862 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1863 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1867 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1869 if (shift == 0)
1870 return;
1872 if (glyph_index->start > index)
1873 glyph_index->start += shift;
1874 if (glyph_index->base > index)
1875 glyph_index->base+= shift;
1876 if (glyph_index->end > index)
1877 glyph_index->end+= shift;
1878 if (glyph_index->ralf > index)
1879 glyph_index->ralf+= shift;
1880 if (glyph_index->blwf > index)
1881 glyph_index->blwf+= shift;
1882 if (glyph_index->pref > index)
1883 glyph_index->pref+= shift;
1886 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 )
1888 int index = glyph_index->start;
1890 if (!feature)
1891 return;
1893 while(index <= glyph_index->end)
1895 INT nextIndex;
1896 INT prevCount = *pcGlyphs;
1897 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1898 if (nextIndex > GSUB_E_NOGLYPH)
1900 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1901 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1902 index = nextIndex;
1904 else
1905 index++;
1909 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1911 int i = 0;
1912 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)))))
1913 i++;
1914 if (index + i <= end-1)
1915 return index + i;
1916 else
1917 return -1;
1920 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)
1922 INT index, nextIndex;
1923 INT count,g_offset;
1925 count = syllable->base - syllable->start;
1927 g_offset = 0;
1928 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1929 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1931 INT prevCount = *pcGlyphs;
1932 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1933 if (nextIndex > GSUB_E_NOGLYPH)
1935 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1936 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1937 g_offset += (*pcGlyphs - prevCount);
1940 index+=2;
1941 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1945 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)
1947 INT nextIndex;
1948 INT prevCount = *pcGlyphs;
1950 if (syllable->ralf >= 0)
1952 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1953 if (nextIndex > GSUB_E_NOGLYPH)
1955 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1956 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1961 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1963 int i = 0;
1964 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1965 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1966 is_consonant(lexical(pwChars[index+i+1])))))
1967 i++;
1968 if (index + i <= end-1)
1969 return index+i;
1970 else
1971 return -1;
1974 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)
1976 INT index, nextIndex;
1977 INT count, g_offset=0;
1978 INT ralf = syllable->ralf;
1980 count = syllable->end - syllable->base;
1982 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
1984 while (index >= 0)
1986 INT prevCount = *pcGlyphs;
1987 if (ralf >=0 && ralf < index)
1989 g_offset--;
1990 ralf = -1;
1993 if (!modern)
1995 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1996 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1997 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2000 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2001 if (nextIndex > GSUB_E_NOGLYPH)
2003 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2004 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2005 g_offset += (*pcGlyphs - prevCount);
2007 else if (!modern)
2009 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2010 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2011 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2014 index+=2;
2015 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2019 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)
2021 int c;
2022 int overall_shift = 0;
2023 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, "locl"):NULL;
2024 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, "nukt");
2025 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, "akhn");
2026 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, "rkrf"):NULL;
2027 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, "pstf");
2028 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, "vatu"):NULL;
2029 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, "cjct"):NULL;
2030 BOOL rphf = (load_OT_feature(hdc, psa, psc, "rphf") != NULL);
2031 BOOL pref = (load_OT_feature(hdc, psa, psc, "pref") != NULL);
2032 BOOL blwf = (load_OT_feature(hdc, psa, psc, "blwf") != NULL);
2033 BOOL half = (load_OT_feature(hdc, psa, psc, "half") != NULL);
2034 IndicSyllable glyph_indexs;
2036 for (c = 0; c < syllable_count; c++)
2038 int old_end;
2039 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2040 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2041 old_end = glyph_indexs.end;
2043 if (locl)
2045 TRACE("applying feature locl\n");
2046 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2048 if (nukt)
2050 TRACE("applying feature nukt\n");
2051 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2053 if (akhn)
2055 TRACE("applying feature akhn\n");
2056 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2059 if (rphf)
2060 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2061 if (rkrf)
2063 TRACE("applying feature rkrf\n");
2064 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2066 if (pref)
2067 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2068 if (blwf)
2070 if (!modern)
2071 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2073 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2076 if (half)
2077 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2078 if (pstf)
2080 TRACE("applying feature pstf\n");
2081 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2083 if (vatu)
2085 TRACE("applying feature vatu\n");
2086 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2088 if (cjct)
2090 TRACE("applying feature cjct\n");
2091 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2094 if (second_reorder)
2095 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2097 overall_shift += glyph_indexs.end - old_end;
2101 static inline int unicode_lex(WCHAR c)
2103 int type;
2105 if (!c) return lex_Generic;
2106 if (c == 0x200D) return lex_ZWJ;
2107 if (c == 0x200C) return lex_ZWNJ;
2108 if (c == 0x00A0) return lex_NBSP;
2110 type = get_table_entry( indic_syllabic_table, c );
2112 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2114 switch( type )
2116 case 0x0d07: /* Unknown */
2117 case 0x0e07: /* Unknwon */
2118 default: return lex_Generic;
2119 case 0x0001:
2120 case 0x0002:
2121 case 0x0011:
2122 case 0x0012:
2123 case 0x0013:
2124 case 0x0014: return lex_Modifier;
2125 case 0x0003:
2126 case 0x0009:
2127 case 0x000a:
2128 case 0x000b:
2129 case 0x000d:
2130 case 0x000e:
2131 case 0x000f:
2132 case 0x0010: return lex_Consonant;
2133 case 0x0004: return lex_Nukta;
2134 case 0x0005: return lex_Halant;
2135 case 0x0006:
2136 case 0x0008: return lex_Vowel;
2137 case 0x0007:
2138 case 0x0107: return lex_Matra_post;
2139 case 0x0207:
2140 case 0x0307: return lex_Matra_pre;
2141 case 0x0807:
2142 case 0x0907:
2143 case 0x0a07:
2144 case 0x0b07:
2145 case 0x0c07:
2146 case 0x0407: return lex_Composed_Vowel;
2147 case 0x0507: return lex_Matra_above;
2148 case 0x0607: return lex_Matra_below;
2149 case 0x000c: return lex_Ra;
2153 static int sinhala_lex(WCHAR c)
2155 switch (c)
2157 case 0x0DDA:
2158 case 0x0DDD:
2159 case 0x0DDC:
2160 case 0x0DDE: return lex_Matra_post;
2161 default:
2162 return unicode_lex(c);
2166 static const VowelComponents Sinhala_vowels[] = {
2167 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2168 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2169 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2170 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2171 {0x0000, {0x0000,0x0000,0x0}}};
2173 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2175 int cCount = cChars;
2176 int i;
2177 WCHAR *input;
2178 IndicSyllable *syllables = NULL;
2179 int syllable_count = 0;
2181 if (*pcGlyphs != cChars)
2183 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2184 return;
2187 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2189 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2191 /* Step 1: Decompose multi part vowels */
2192 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2194 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2196 /* Step 2: Reorder within Syllables */
2197 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2198 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2200 /* Step 3: Strip dangling joiners */
2201 for (i = 0; i < cCount; i++)
2203 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2204 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2205 input[i] = 0x0020;
2208 /* Step 4: Base Form application to syllables */
2209 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2210 *pcGlyphs = cCount;
2211 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2213 HeapFree(GetProcessHeap(),0,input);
2214 HeapFree(GetProcessHeap(),0,syllables);
2217 static int devanagari_lex(WCHAR c)
2219 switch (c)
2221 case 0x0930: return lex_Ra;
2222 default:
2223 return unicode_lex(c);
2227 static const ConsonantComponents Devanagari_consonants[] ={
2228 {{0x0928, 0x093C, 0x00000}, 0x0929},
2229 {{0x0930, 0x093C, 0x00000}, 0x0931},
2230 {{0x0933, 0x093C, 0x00000}, 0x0934},
2231 {{0x0915, 0x093C, 0x00000}, 0x0958},
2232 {{0x0916, 0x093C, 0x00000}, 0x0959},
2233 {{0x0917, 0x093C, 0x00000}, 0x095A},
2234 {{0x091C, 0x093C, 0x00000}, 0x095B},
2235 {{0x0921, 0x093C, 0x00000}, 0x095C},
2236 {{0x0922, 0x093C, 0x00000}, 0x095D},
2237 {{0x092B, 0x093C, 0x00000}, 0x095E},
2238 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2240 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2242 int cCount = cChars;
2243 WCHAR *input;
2244 IndicSyllable *syllables = NULL;
2245 int syllable_count = 0;
2246 BOOL modern = get_GSUB_Indic2(psa, psc);
2248 if (*pcGlyphs != cChars)
2250 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2251 return;
2254 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2255 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2257 /* Step 1: Compose Consonant and Nukta */
2258 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2259 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2261 /* Step 2: Reorder within Syllables */
2262 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2263 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2264 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2265 *pcGlyphs = cCount;
2267 /* Step 3: Base Form application to syllables */
2268 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2270 HeapFree(GetProcessHeap(),0,input);
2271 HeapFree(GetProcessHeap(),0,syllables);
2274 static int bengali_lex(WCHAR c)
2276 switch (c)
2278 case 0x09B0: return lex_Ra;
2279 default:
2280 return unicode_lex(c);
2284 static const VowelComponents Bengali_vowels[] = {
2285 {0x09CB, {0x09C7,0x09BE,0x0000}},
2286 {0x09CC, {0x09C7,0x09D7,0x0000}},
2287 {0x0000, {0x0000,0x0000,0x0000}}};
2289 static const ConsonantComponents Bengali_consonants[] = {
2290 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2291 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2292 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2293 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2294 {{0x0000,0x0000,0x0000}, 0x0000}};
2296 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2298 int cCount = cChars;
2299 WCHAR *input;
2300 IndicSyllable *syllables = NULL;
2301 int syllable_count = 0;
2302 BOOL modern = get_GSUB_Indic2(psa, psc);
2304 if (*pcGlyphs != cChars)
2306 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2307 return;
2310 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2311 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2313 /* Step 1: Decompose Vowels and Compose Consonants */
2314 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2315 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2316 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2318 /* Step 2: Reorder within Syllables */
2319 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2320 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2321 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2322 *pcGlyphs = cCount;
2324 /* Step 3: Initial form is only applied to the beginning of words */
2325 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2327 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2329 int index = cCount;
2330 int gCount = 1;
2331 if (index > 0) index++;
2333 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2337 /* Step 4: Base Form application to syllables */
2338 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2340 HeapFree(GetProcessHeap(),0,input);
2341 HeapFree(GetProcessHeap(),0,syllables);
2344 static int gurmukhi_lex(WCHAR c)
2346 if (c == 0x0A71)
2347 return lex_Modifier;
2348 else
2349 return unicode_lex(c);
2352 static const ConsonantComponents Gurmukhi_consonants[] = {
2353 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2354 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2355 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2356 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2357 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2358 {{0x0000,0x0000,0x0000}, 0x0000}};
2360 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2362 int cCount = cChars;
2363 WCHAR *input;
2364 IndicSyllable *syllables = NULL;
2365 int syllable_count = 0;
2366 BOOL modern = get_GSUB_Indic2(psa, psc);
2368 if (*pcGlyphs != cChars)
2370 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2371 return;
2374 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2375 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2377 /* Step 1: Compose Consonants */
2378 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2379 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2381 /* Step 2: Reorder within Syllables */
2382 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2383 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2384 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2385 *pcGlyphs = cCount;
2387 /* Step 3: Base Form application to syllables */
2388 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2390 HeapFree(GetProcessHeap(),0,input);
2391 HeapFree(GetProcessHeap(),0,syllables);
2394 static int gujarati_lex(WCHAR c)
2396 switch (c)
2398 case 0x0AB0: return lex_Ra;
2399 default:
2400 return unicode_lex(c);
2404 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2406 int cCount = cChars;
2407 WCHAR *input;
2408 IndicSyllable *syllables = NULL;
2409 int syllable_count = 0;
2410 BOOL modern = get_GSUB_Indic2(psa, psc);
2412 if (*pcGlyphs != cChars)
2414 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2415 return;
2418 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2419 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2421 /* Step 1: Reorder within Syllables */
2422 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2423 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2424 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2425 *pcGlyphs = cCount;
2427 /* Step 2: Base Form application to syllables */
2428 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2430 HeapFree(GetProcessHeap(),0,input);
2431 HeapFree(GetProcessHeap(),0,syllables);
2434 static int oriya_lex(WCHAR c)
2436 switch (c)
2438 case 0x0B30: return lex_Ra;
2439 default:
2440 return unicode_lex(c);
2444 static const VowelComponents Oriya_vowels[] = {
2445 {0x0B48, {0x0B47,0x0B56,0x0000}},
2446 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2447 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2448 {0x0000, {0x0000,0x0000,0x0000}}};
2450 static const ConsonantComponents Oriya_consonants[] = {
2451 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2452 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2453 {{0x0000,0x0000,0x0000}, 0x0000}};
2455 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2457 int cCount = cChars;
2458 WCHAR *input;
2459 IndicSyllable *syllables = NULL;
2460 int syllable_count = 0;
2461 BOOL modern = get_GSUB_Indic2(psa, psc);
2463 if (*pcGlyphs != cChars)
2465 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2466 return;
2469 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2470 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2472 /* Step 1: Decompose Vowels and Compose Consonants */
2473 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2474 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2475 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2477 /* Step 2: Reorder within Syllables */
2478 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2479 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2480 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2481 *pcGlyphs = cCount;
2483 /* Step 3: Base Form application to syllables */
2484 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2486 HeapFree(GetProcessHeap(),0,input);
2487 HeapFree(GetProcessHeap(),0,syllables);
2490 static int tamil_lex(WCHAR c)
2492 return unicode_lex(c);
2495 static const VowelComponents Tamil_vowels[] = {
2496 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2497 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2498 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2499 {0x0000, {0x0000,0x0000,0x0000}}};
2501 static const ConsonantComponents Tamil_consonants[] = {
2502 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2503 {{0x0000,0x0000,0x0000}, 0x0000}};
2505 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2507 int cCount = cChars;
2508 WCHAR *input;
2509 IndicSyllable *syllables = NULL;
2510 int syllable_count = 0;
2511 BOOL modern = get_GSUB_Indic2(psa, psc);
2513 if (*pcGlyphs != cChars)
2515 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2516 return;
2519 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2520 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2522 /* Step 1: Decompose Vowels and Compose Consonants */
2523 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2524 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2525 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2527 /* Step 2: Reorder within Syllables */
2528 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2529 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2530 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2531 *pcGlyphs = cCount;
2533 /* Step 3: Base Form application to syllables */
2534 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2536 HeapFree(GetProcessHeap(),0,input);
2537 HeapFree(GetProcessHeap(),0,syllables);
2540 static int telugu_lex(WCHAR c)
2542 switch (c)
2544 case 0x0C43:
2545 case 0x0C44: return lex_Modifier;
2546 default:
2547 return unicode_lex(c);
2551 static const VowelComponents Telugu_vowels[] = {
2552 {0x0C48, {0x0C46,0x0C56,0x0000}},
2553 {0x0000, {0x0000,0x0000,0x0000}}};
2555 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2557 int cCount = cChars;
2558 WCHAR *input;
2559 IndicSyllable *syllables = NULL;
2560 int syllable_count = 0;
2561 BOOL modern = get_GSUB_Indic2(psa, psc);
2563 if (*pcGlyphs != cChars)
2565 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2566 return;
2569 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2570 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2572 /* Step 1: Decompose Vowels */
2573 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2574 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2576 /* Step 2: Reorder within Syllables */
2577 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_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;
2582 /* Step 3: Base Form application to syllables */
2583 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2585 HeapFree(GetProcessHeap(),0,input);
2586 HeapFree(GetProcessHeap(),0,syllables);
2589 static int kannada_lex(WCHAR c)
2591 switch (c)
2593 case 0x0CB0: return lex_Ra;
2594 default:
2595 return unicode_lex(c);
2599 static const VowelComponents Kannada_vowels[] = {
2600 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2601 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2602 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2603 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2604 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2605 {0x0000, {0x0000,0x0000,0x0000}}};
2607 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2609 int cCount = cChars;
2610 WCHAR *input;
2611 IndicSyllable *syllables = NULL;
2612 int syllable_count = 0;
2613 BOOL modern = get_GSUB_Indic2(psa, psc);
2615 if (*pcGlyphs != cChars)
2617 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2618 return;
2621 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2622 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2624 /* Step 1: Decompose Vowels */
2625 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2626 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2628 /* Step 2: Reorder within Syllables */
2629 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2630 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2631 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2632 *pcGlyphs = cCount;
2634 /* Step 3: Base Form application to syllables */
2635 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2637 HeapFree(GetProcessHeap(),0,input);
2638 HeapFree(GetProcessHeap(),0,syllables);
2641 static int malayalam_lex(WCHAR c)
2643 return unicode_lex(c);
2646 static const VowelComponents Malayalam_vowels[] = {
2647 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2648 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2649 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2650 {0x0000, {0x0000,0x0000,0x0000}}};
2652 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2654 int cCount = cChars;
2655 WCHAR *input;
2656 IndicSyllable *syllables = NULL;
2657 int syllable_count = 0;
2658 BOOL modern = get_GSUB_Indic2(psa, psc);
2660 if (*pcGlyphs != cChars)
2662 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2663 return;
2666 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2667 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2669 /* Step 1: Decompose Vowels */
2670 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2671 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2673 /* Step 2: Reorder within Syllables */
2674 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2675 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2676 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2677 *pcGlyphs = cCount;
2679 /* Step 3: Base Form application to syllables */
2680 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2682 HeapFree(GetProcessHeap(),0,input);
2683 HeapFree(GetProcessHeap(),0,syllables);
2686 static int khmer_lex(WCHAR c)
2688 return unicode_lex(c);
2691 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2693 int cCount = cChars;
2694 WCHAR *input;
2695 IndicSyllable *syllables = NULL;
2696 int syllable_count = 0;
2698 if (*pcGlyphs != cChars)
2700 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2701 return;
2704 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2705 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2707 /* Step 1: Reorder within Syllables */
2708 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2709 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2710 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2711 *pcGlyphs = cCount;
2713 /* Step 2: Base Form application to syllables */
2714 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2716 HeapFree(GetProcessHeap(),0,input);
2717 HeapFree(GetProcessHeap(),0,syllables);
2720 static inline BOOL mongolian_wordbreak(WCHAR chr)
2722 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2725 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2727 INT *context_shape;
2728 INT dirL;
2729 int i;
2731 if (*pcGlyphs != cChars)
2733 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2734 return;
2737 if (!psa->fLogicalOrder && psa->fRTL)
2738 dirL = -1;
2739 else
2740 dirL = 1;
2742 load_ot_tables(hdc, psc);
2744 if (!psc->GSUB_Table)
2745 return;
2747 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2749 for (i = 0; i < cChars; i++)
2751 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2753 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2754 context_shape[i] = Xn;
2755 else
2756 context_shape[i] = Xl;
2758 else
2760 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2761 context_shape[i] = Xr;
2762 else
2763 context_shape[i] = Xm;
2767 /* Contextual Shaping */
2768 i = 0;
2769 while(i < *pcGlyphs)
2771 INT nextIndex;
2772 INT prevCount = *pcGlyphs;
2773 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2774 if (nextIndex > GSUB_E_NOGLYPH)
2776 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2777 i = nextIndex;
2779 else
2780 i++;
2783 HeapFree(GetProcessHeap(),0,context_shape);
2786 static void ShapeCharGlyphProp_Default( 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)
2788 int i,k;
2790 for (i = 0; i < cGlyphs; i++)
2792 int char_index[20];
2793 int char_count = 0;
2795 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2796 if (k>=0)
2798 for (; k < cChars && pwLogClust[k] == i; k++)
2799 char_index[char_count++] = k;
2802 if (char_count == 0)
2803 continue;
2805 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2807 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2808 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2810 else
2811 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2814 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2815 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2818 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 )
2820 int i,k;
2821 int initGlyph, finaGlyph;
2822 INT dirR, dirL;
2823 BYTE *spaces;
2825 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2826 memset(spaces,0,cGlyphs);
2828 if (!psa->fLogicalOrder && psa->fRTL)
2830 initGlyph = cGlyphs-1;
2831 finaGlyph = 0;
2832 dirR = 1;
2833 dirL = -1;
2835 else
2837 initGlyph = 0;
2838 finaGlyph = cGlyphs-1;
2839 dirR = -1;
2840 dirL = 1;
2843 for (i = 0; i < cGlyphs; i++)
2845 for (k = 0; k < cChars; k++)
2846 if (pwLogClust[k] == i)
2848 if (pwcChars[k] == 0x0020)
2849 spaces[i] = 1;
2853 for (i = 0; i < cGlyphs; i++)
2855 int char_index[20];
2856 int char_count = 0;
2857 BOOL isInit, isFinal;
2859 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2860 if (k>=0)
2862 for (; k < cChars && pwLogClust[k] == i; k++)
2863 char_index[char_count++] = k;
2866 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2867 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2869 if (char_count == 0)
2870 continue;
2872 if (char_count == 1)
2874 if (pwcChars[char_index[0]] == 0x0020) /* space */
2876 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2877 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2879 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2880 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2881 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2883 if (!isInit && !isFinal)
2884 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2885 else if (isInit)
2886 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2887 else
2888 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2890 else if (!isInit)
2892 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2893 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2894 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2895 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2896 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2897 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2898 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2899 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2900 else
2901 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2903 else if (!isInit && !isFinal)
2904 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2905 else
2906 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2908 else if (char_count == 2)
2910 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2911 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2912 else if (!isInit)
2913 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2914 else
2915 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2917 else if (!isInit && !isFinal)
2918 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2919 else
2920 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2923 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2924 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2925 HeapFree(GetProcessHeap(),0,spaces);
2928 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 )
2930 int i,k;
2932 for (i = 0; i < cGlyphs; i++)
2934 int char_index[20];
2935 int char_count = 0;
2937 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2938 if (k>=0)
2940 for (; k < cChars && pwLogClust[k] == i; k++)
2941 char_index[char_count++] = k;
2944 if (char_count == 0)
2945 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2946 else
2948 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2949 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2950 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2954 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2955 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2958 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 )
2960 int i;
2961 int finaGlyph;
2962 INT dirL;
2964 if (!psa->fLogicalOrder && psa->fRTL)
2966 finaGlyph = 0;
2967 dirL = -1;
2969 else
2971 finaGlyph = cGlyphs-1;
2972 dirL = 1;
2975 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2977 for (i = 0; i < cGlyphs; i++)
2979 int k;
2980 int char_index[20];
2981 int char_count = 0;
2983 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2984 if (k>=0)
2986 for (; k < cChars && pwLogClust[k] == i; k++)
2987 char_index[char_count++] = k;
2990 if (i == finaGlyph)
2991 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2992 else
2993 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2995 if (char_count == 0)
2996 continue;
2998 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2999 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3001 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3002 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3003 pGlyphProp[i].sva.fClusterStart = 0;
3006 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3008 /* Do not allow justification between marks and their base */
3009 for (i = 0; i < cGlyphs; i++)
3011 if (!pGlyphProp[i].sva.fClusterStart)
3012 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3016 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)
3018 int i,k;
3020 for (i = 0; i < cGlyphs; i++)
3022 int char_index[20];
3023 int char_count = 0;
3025 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3026 if (k>=0)
3028 for (; k < cChars && pwLogClust[k] == i; k++)
3029 char_index[char_count++] = k;
3032 if (char_count == 0)
3033 continue;
3035 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3037 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3038 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3040 else
3041 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3043 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3044 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3047 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)
3049 int i,k;
3051 for (i = 0; i < cGlyphs; i++)
3053 int char_index[20];
3054 int char_count = 0;
3056 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3057 if (k>=0)
3059 for (; k < cChars && pwLogClust[k] == i; k++)
3060 char_index[char_count++] = k;
3063 if (char_count == 0)
3064 continue;
3066 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3068 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3069 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3071 else
3072 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3074 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3075 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3077 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3078 for (i = 0; i < cGlyphs; i++)
3080 if (!pGlyphProp[i].sva.fClusterStart)
3082 pGlyphProp[i].sva.fDiacritic = 0;
3083 pGlyphProp[i].sva.fZeroWidth = 0;
3088 static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables, BOOL override_gsub)
3090 int i,k;
3092 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3093 for (i = 0; i < cGlyphs; i++)
3095 int char_index[20];
3096 int char_count = 0;
3098 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3099 if (k>=0)
3101 for (; k < cChars && pwLogClust[k] == i; k++)
3102 char_index[char_count++] = k;
3105 if (override_gsub)
3107 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3108 pGlyphProp[i].sva.fDiacritic = FALSE;
3109 pGlyphProp[i].sva.fZeroWidth = FALSE;
3112 if (char_count == 0)
3114 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3115 continue;
3118 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3120 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3121 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3123 else
3124 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3126 pGlyphProp[i].sva.fClusterStart = 0;
3127 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3128 switch (lexical(pwcChars[char_index[k]]))
3130 case lex_Matra_pre:
3131 case lex_Matra_post:
3132 case lex_Matra_above:
3133 case lex_Matra_below:
3134 case lex_Modifier:
3135 case lex_Halant:
3136 break;
3137 case lex_ZWJ:
3138 case lex_ZWNJ:
3139 /* check for dangling joiners */
3140 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3141 pGlyphProp[i].sva.fClusterStart = 1;
3142 else
3143 k = char_count;
3144 break;
3145 default:
3146 pGlyphProp[i].sva.fClusterStart = 1;
3147 break;
3151 if (use_syllables)
3153 IndicSyllable *syllables = NULL;
3154 int syllable_count = 0;
3155 BOOL modern = get_GSUB_Indic2(psa, psc);
3157 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3159 for (i = 0; i < syllable_count; i++)
3161 int j;
3162 WORD g = pwLogClust[syllables[i].start];
3163 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3165 if (pwLogClust[j] != g)
3167 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3168 pwLogClust[j] = g;
3173 HeapFree(GetProcessHeap(), 0, syllables);
3176 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3179 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 )
3181 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3184 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 )
3186 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3189 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 )
3191 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3194 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 )
3196 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3199 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 )
3201 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3204 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 )
3206 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3209 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 )
3211 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3214 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 )
3216 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3219 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 )
3221 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3224 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 )
3226 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3229 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 )
3231 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3234 void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp)
3236 if (ShapingData[psa->eScript].charGlyphPropProc)
3237 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3238 else
3239 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3242 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3244 load_ot_tables(hdc, psc);
3246 if (ShapingData[psa->eScript].contextProc)
3247 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3250 static void SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, const TEXTRANGE_PROPERTIES *rpRangeProperties, WORD *pwLogClust)
3252 int i;
3253 INT dirL;
3255 if (!rpRangeProperties)
3256 return;
3258 load_ot_tables(hdc, psc);
3260 if (!psc->GSUB_Table)
3261 return;
3263 if (!psa->fLogicalOrder && psa->fRTL)
3264 dirL = -1;
3265 else
3266 dirL = 1;
3268 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3270 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3271 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3275 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3277 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3278 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3280 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3283 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3285 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3286 int i;
3287 INT dirL;
3288 LPOUTLINETEXTMETRICW lpotm;
3289 LOGFONTW lf;
3290 HFONT hfont;
3292 rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3294 if (!rpRangeProperties)
3295 return;
3297 load_ot_tables(hdc, psc);
3299 if (!psc->GPOS_Table)
3300 return;
3302 i = GetOutlineTextMetricsW( hdc, 0, NULL);
3303 lpotm = HeapAlloc(GetProcessHeap(),0,i);
3304 GetOutlineTextMetricsW( hdc, i, lpotm);
3305 hfont = GetCurrentObject(hdc, OBJ_FONT);
3306 GetObjectW(hfont, sizeof(lf), &lf);
3308 if (!psa->fLogicalOrder && psa->fRTL)
3309 dirL = -1;
3310 else
3311 dirL = 1;
3313 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3315 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3317 LoadedFeature *feature;
3319 feature = load_OT_feature(hdc, psa, psc, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3320 if (!feature)
3321 continue;
3323 GPOS_apply_feature(lpotm, &lf, piAdvance, psc->GPOS_Table, feature, pwGlyphs, dirL, cGlyphs, pGoffset);
3328 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3330 LoadedFeature *feature;
3331 int i;
3333 if (!ShapingData[psa->eScript].requiredFeatures)
3334 return S_OK;
3336 load_ot_tables(hdc, psc);
3338 /* we need to have at least one of the required features */
3339 i = 0;
3340 while (ShapingData[psa->eScript].requiredFeatures[i])
3342 feature = load_OT_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3343 if (feature)
3344 return S_OK;
3345 i++;
3348 return USP_E_SCRIPT_NOT_IN_FONT;
3351 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3352 SCRIPT_ANALYSIS *psa, int cMaxTags,
3353 OPENTYPE_TAG *pScriptTags, int *pcTags)
3355 HRESULT hr;
3356 OPENTYPE_TAG searching = 0x00000000;
3358 load_ot_tables(hdc, psc);
3360 if (psa && scriptInformation[psa->eScript].scriptTag)
3361 searching = scriptInformation[psa->eScript].scriptTag;
3363 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3364 if (FAILED(hr))
3365 *pcTags = 0;
3366 return hr;
3369 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3370 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3371 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3372 int *pcTags)
3374 HRESULT hr;
3375 OPENTYPE_TAG searching = 0x00000000;
3376 BOOL fellback = FALSE;
3378 load_ot_tables(hdc, psc);
3380 if (psa && psc->userLang != 0)
3381 searching = psc->userLang;
3383 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3384 if (FAILED(hr))
3386 fellback = TRUE;
3387 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3390 if (FAILED(hr) || fellback)
3391 *pcTags = 0;
3392 if (SUCCEEDED(hr) && fellback && psa)
3393 hr = E_INVALIDARG;
3394 return hr;
3397 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3398 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3399 OPENTYPE_TAG tagLangSys, int cMaxTags,
3400 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3402 HRESULT hr;
3403 BOOL filter = FALSE;
3405 load_ot_tables(hdc, psc);
3407 if (psa && scriptInformation[psa->eScript].scriptTag)
3409 FIXME("Filtering not implemented\n");
3410 filter = TRUE;
3413 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL);
3415 if (FAILED(hr))
3416 *pcTags = 0;
3417 return hr;