msi/tests: Test for error control flag handling.
[wine.git] / dlls / usp10 / shape.c
blob3fdf84baab31193bce99f0247022f04dc631c45b
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_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
63 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
65 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
67 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
68 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
78 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 );
79 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 );
80 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 );
81 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 );
82 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 );
83 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 );
84 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 );
85 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 );
87 extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
88 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
89 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
91 enum joining_types {
92 jtU,
93 jtT,
94 jtR,
95 jtL,
96 jtD,
97 jtC
100 enum joined_forms {
101 Xn=0,
105 /* Syriac Alaph */
106 Afj,
107 Afn,
111 typedef struct tagVowelComponents
113 WCHAR base;
114 WCHAR parts[3];
115 } VowelComponents;
117 typedef struct tagConsonantComponents
119 WCHAR parts[3];
120 WCHAR output;
121 } ConsonantComponents;
123 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
125 typedef int (*combining_lexical_function)(WCHAR c);
127 /* the orders of joined_forms and contextual_features need to line up */
128 static const char* contextual_features[] =
130 "isol",
131 "fina",
132 "init",
133 "medi",
134 /* Syriac Alaph */
135 "med2",
136 "fin2",
137 "fin3"
140 static OPENTYPE_FEATURE_RECORD standard_features[] =
142 { MS_MAKE_TAG('c','c','m','p'), 1},
143 { MS_MAKE_TAG('l','o','c','l'), 1},
146 static OPENTYPE_FEATURE_RECORD latin_features[] =
148 { MS_MAKE_TAG('l','o','c','l'), 1},
149 { MS_MAKE_TAG('c','c','m','p'), 1},
150 { MS_MAKE_TAG('l','i','g','a'), 1},
151 { MS_MAKE_TAG('c','l','i','g'), 1},
154 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
156 { MS_MAKE_TAG('k','e','r','n'), 1},
157 { MS_MAKE_TAG('m','a','r','k'), 1},
158 { MS_MAKE_TAG('m','k','m','k'), 1},
161 static OPENTYPE_FEATURE_RECORD arabic_features[] =
163 { MS_MAKE_TAG('r','l','i','g'), 1},
164 { MS_MAKE_TAG('c','a','l','t'), 1},
165 { MS_MAKE_TAG('l','i','g','a'), 1},
166 { MS_MAKE_TAG('d','l','i','g'), 1},
167 { MS_MAKE_TAG('c','s','w','h'), 1},
168 { MS_MAKE_TAG('m','s','e','t'), 1},
171 static const char* required_arabic_features[] =
173 "fina",
174 "init",
175 "medi",
176 "rlig",
177 NULL
180 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
182 { MS_MAKE_TAG('c','u','r','s'), 1},
183 { MS_MAKE_TAG('k','e','r','n'), 1},
184 { MS_MAKE_TAG('m','a','r','k'), 1},
185 { MS_MAKE_TAG('m','k','m','k'), 1},
188 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
190 { MS_MAKE_TAG('c','c','m','p'), 1},
191 { MS_MAKE_TAG('d','l','i','g'), 0},
194 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
196 { MS_MAKE_TAG('k','e','r','n'), 1},
197 { MS_MAKE_TAG('m','a','r','k'), 1},
200 static OPENTYPE_FEATURE_RECORD syriac_features[] =
202 { MS_MAKE_TAG('r','l','i','g'), 1},
203 { MS_MAKE_TAG('c','a','l','t'), 1},
204 { MS_MAKE_TAG('l','i','g','a'), 1},
205 { MS_MAKE_TAG('d','l','i','g'), 1},
208 static const char* required_syriac_features[] =
210 "fina",
211 "fin2",
212 "fin3",
213 "init",
214 "medi",
215 "med2",
216 "rlig",
217 NULL
220 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
222 { MS_MAKE_TAG('k','e','r','n'), 1},
223 { MS_MAKE_TAG('m','a','r','k'), 1},
224 { MS_MAKE_TAG('m','k','m','k'), 1},
227 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
229 /* Presentation forms */
230 { MS_MAKE_TAG('b','l','w','s'), 1},
231 { MS_MAKE_TAG('a','b','v','s'), 1},
232 { MS_MAKE_TAG('p','s','t','s'), 1},
235 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
237 { MS_MAKE_TAG('a','b','v','s'), 1},
238 { MS_MAKE_TAG('b','l','w','s'), 1},
241 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
243 { MS_MAKE_TAG('a','b','v','m'), 1},
244 { MS_MAKE_TAG('b','l','w','m'), 1},
247 static OPENTYPE_FEATURE_RECORD phags_features[] =
249 { MS_MAKE_TAG('a','b','v','s'), 1},
250 { MS_MAKE_TAG('b','l','w','s'), 1},
251 { MS_MAKE_TAG('c','a','l','t'), 1},
254 static OPENTYPE_FEATURE_RECORD thai_features[] =
256 { MS_MAKE_TAG('c','c','m','p'), 1},
259 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
261 { MS_MAKE_TAG('k','e','r','n'), 1},
262 { MS_MAKE_TAG('m','a','r','k'), 1},
263 { MS_MAKE_TAG('m','k','m','k'), 1},
266 static const char* required_lao_features[] =
268 "ccmp",
269 NULL
272 static const char* required_devanagari_features[] =
274 "nukt",
275 "akhn",
276 "rphf",
277 "blwf",
278 "half",
279 "vatu",
280 "pres",
281 "abvs",
282 "blws",
283 "psts",
284 "haln",
285 NULL
288 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
290 { MS_MAKE_TAG('p','r','e','s'), 1},
291 { MS_MAKE_TAG('a','b','v','s'), 1},
292 { MS_MAKE_TAG('b','l','w','s'), 1},
293 { MS_MAKE_TAG('p','s','t','s'), 1},
294 { MS_MAKE_TAG('h','a','l','n'), 1},
295 { MS_MAKE_TAG('c','a','l','t'), 1},
298 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
300 { MS_MAKE_TAG('k','e','r','n'), 1},
301 { MS_MAKE_TAG('d','i','s','t'), 1},
302 { MS_MAKE_TAG('a','b','v','m'), 1},
303 { MS_MAKE_TAG('b','l','w','m'), 1},
306 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
308 { MS_MAKE_TAG('l','i','g','a'), 1},
309 { MS_MAKE_TAG('c','l','i','g'), 1},
312 static const char* required_bengali_features[] =
314 "nukt",
315 "akhn",
316 "rphf",
317 "blwf",
318 "half",
319 "vatu",
320 "pstf",
321 "init",
322 "abvs",
323 "blws",
324 "psts",
325 "haln",
326 NULL
329 static const char* required_gurmukhi_features[] =
331 "nukt",
332 "akhn",
333 "rphf",
334 "blwf",
335 "half",
336 "pstf",
337 "vatu",
338 "cjct",
339 "pres",
340 "abvs",
341 "blws",
342 "psts",
343 "haln",
344 "calt",
345 NULL
348 static const char* required_oriya_features[] =
350 "nukt",
351 "akhn",
352 "rphf",
353 "blwf",
354 "pstf",
355 "cjct",
356 "pres",
357 "abvs",
358 "blws",
359 "psts",
360 "haln",
361 "calt",
362 NULL
365 static const char* required_tamil_features[] =
367 "nukt",
368 "akhn",
369 "rphf",
370 "pref",
371 "half",
372 "pres",
373 "abvs",
374 "blws",
375 "psts",
376 "haln",
377 "calt",
378 NULL
381 static const char* required_telugu_features[] =
383 "nukt",
384 "akhn",
385 "rphf",
386 "pref",
387 "half",
388 "pstf",
389 "cjct",
390 "pres",
391 "abvs",
392 "blws",
393 "psts",
394 "haln",
395 "calt",
396 NULL
399 static OPENTYPE_FEATURE_RECORD khmer_features[] =
401 { MS_MAKE_TAG('p','r','e','s'), 1},
402 { MS_MAKE_TAG('b','l','w','s'), 1},
403 { MS_MAKE_TAG('a','b','v','s'), 1},
404 { MS_MAKE_TAG('p','s','t','s'), 1},
405 { MS_MAKE_TAG('c','l','i','g'), 1},
408 static const char* required_khmer_features[] =
410 "pref",
411 "blwf",
412 "abvf",
413 "pstf",
414 "pres",
415 "blws",
416 "abvs",
417 "psts",
418 "clig",
419 NULL
422 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
424 { MS_MAKE_TAG('d','i','s','t'), 1},
425 { MS_MAKE_TAG('b','l','w','m'), 1},
426 { MS_MAKE_TAG('a','b','v','m'), 1},
427 { MS_MAKE_TAG('m','k','m','k'), 1},
430 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
432 { MS_MAKE_TAG('c','c','m','p'), 1},
433 { MS_MAKE_TAG('l','o','c','l'), 1},
434 { MS_MAKE_TAG('c','a','l','t'), 1},
435 { MS_MAKE_TAG('l','i','g','a'), 1},
438 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
440 { MS_MAKE_TAG('c','c','m','p'), 1},
441 { MS_MAKE_TAG('l','o','c','l'), 1},
442 { MS_MAKE_TAG('c','a','l','t'), 1},
443 { MS_MAKE_TAG('r','l','i','g'), 1},
446 typedef struct ScriptShapeDataTag {
447 TEXTRANGE_PROPERTIES defaultTextRange;
448 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
449 const char** requiredFeatures;
450 OPENTYPE_TAG newOtTag;
451 ContextualShapingProc contextProc;
452 ShapeCharGlyphPropProc charGlyphPropProc;
453 } ScriptShapeData;
455 /* in order of scripts */
456 static const ScriptShapeData ShapingData[] =
458 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
459 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
460 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
461 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
462 {{ standard_features, 2}, {NULL, 0}, NULL, 0, ContextualShape_Control, ShapeCharGlyphProp_Control},
463 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
464 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
465 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
466 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
467 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
468 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
469 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
470 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
471 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
472 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
473 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
474 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
475 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
476 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
477 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
478 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
479 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
480 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
481 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
482 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
483 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
497 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
498 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
499 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
500 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
501 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
502 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
503 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
504 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
505 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
506 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
511 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
512 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
513 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
516 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
521 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, 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 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
532 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
533 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
534 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
535 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
536 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
537 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
538 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
539 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
542 extern scriptData scriptInformation[];
544 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
546 int i;
547 int out_index = GSUB_E_NOGLYPH;
549 TRACE("%i lookups\n", feature->lookup_count);
550 for (i = 0; i < feature->lookup_count; i++)
552 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
553 if (out_index != GSUB_E_NOGLYPH)
554 break;
556 if (out_index == GSUB_E_NOGLYPH)
557 TRACE("lookups found no glyphs\n");
558 else
560 int out2;
561 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
562 if (out2!=GSUB_E_NOGLYPH)
563 out_index = out2;
565 return out_index;
568 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
570 UINT charset;
572 if (psc->userScript != 0)
574 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
575 return ShapingData[psa->eScript].newOtTag;
576 else
577 return psc->userScript;
580 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
581 return ShapingData[psa->eScript].newOtTag;
583 if (scriptInformation[psa->eScript].scriptTag)
584 return scriptInformation[psa->eScript].scriptTag;
587 * fall back to the font charset
589 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
590 switch (charset)
592 case ANSI_CHARSET:
593 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
594 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
595 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
596 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
597 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
598 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
599 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
600 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
601 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
602 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
603 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
604 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
605 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
606 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
607 default: return MS_MAKE_TAG('l','a','t','n');
611 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
613 LoadedFeature *feature = NULL;
615 if (psc->GSUB_Table || psc->GPOS_Table)
617 int attempt = 2;
618 OPENTYPE_TAG tags;
619 OPENTYPE_TAG language;
620 OPENTYPE_TAG script = 0x00000000;
621 int cTags;
625 script = get_opentype_script(hdc,psa,psc,(attempt==2));
626 if (psc->userLang != 0)
627 language = psc->userLang;
628 else
629 language = MS_MAKE_TAG('d','f','l','t');
630 attempt--;
632 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
634 } while(attempt && !feature);
636 /* try in the default (latin) table */
637 if (!feature && !script)
638 OpenType_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
641 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
642 return feature;
645 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)
647 LoadedFeature *feature;
649 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
650 if (!feature)
651 return GSUB_E_NOFEATURE;
653 TRACE("applying feature %s\n",feat);
654 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
657 static VOID *load_gsub_table(HDC hdc)
659 VOID* GSUB_Table = NULL;
660 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
661 if (length != GDI_ERROR)
663 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
664 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
665 TRACE("Loaded GSUB table of %i bytes\n",length);
667 return GSUB_Table;
670 static VOID *load_gpos_table(HDC hdc)
672 VOID* GPOS_Table = NULL;
673 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
674 if (length != GDI_ERROR)
676 GPOS_Table = HeapAlloc(GetProcessHeap(),0,length);
677 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
678 TRACE("Loaded GPOS table of %i bytes\n",length);
680 return GPOS_Table;
683 static VOID *load_gdef_table(HDC hdc)
685 VOID* GDEF_Table = NULL;
686 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
687 if (length != GDI_ERROR)
689 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
690 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
691 TRACE("Loaded GDEF table of %i bytes\n",length);
693 return GDEF_Table;
696 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
698 if (!psc->GSUB_Table)
699 psc->GSUB_Table = load_gsub_table(hdc);
700 if (!psc->GPOS_Table)
701 psc->GPOS_Table = load_gpos_table(hdc);
702 if (!psc->GDEF_Table)
703 psc->GDEF_Table = load_gdef_table(hdc);
706 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)
708 WORD *glyphs;
709 INT glyph_count = count;
710 INT rc;
712 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
713 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
714 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
715 if (rc > GSUB_E_NOGLYPH)
716 rc = count - glyph_count;
717 else
718 rc = 0;
720 HeapFree(GetProcessHeap(),0,glyphs);
721 return rc;
724 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
726 int i;
728 for (i = 0; i < cGlyphs; i++)
730 if (!pGlyphProp[i].sva.fClusterStart)
732 int j;
733 for (j = 0; j < cChars; j++)
735 if (pwLogClust[j] == i)
737 int k = j;
738 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
739 k-=1;
740 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
741 pwLogClust[j] = pwLogClust[k];
748 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
750 if (changeCount == 0)
751 return;
752 else
754 int i;
755 int target_glyph = nextIndex - write_dir;
756 int seeking_glyph;
757 int target_index = -1;
758 int replacing_glyph = -1;
759 int changed = 0;
760 int top_logclust = 0;
762 if (changeCount > 0)
764 if (write_dir > 0)
765 target_glyph = nextIndex - changeCount;
766 else
767 target_glyph = nextIndex + (changeCount + 1);
770 seeking_glyph = target_glyph;
771 for (i = 0; i < chars; i++)
772 if (pwLogClust[i] > top_logclust)
773 top_logclust = pwLogClust[i];
775 do {
776 if (write_dir > 0)
777 for (i = 0; i < chars; i++)
779 if (pwLogClust[i] == seeking_glyph)
781 target_index = i;
782 break;
785 else
786 for (i = chars - 1; i >= 0; i--)
788 if (pwLogClust[i] == seeking_glyph)
790 target_index = i;
791 break;
794 if (target_index == -1)
795 seeking_glyph ++;
797 while (target_index == -1 && seeking_glyph <= top_logclust);
799 if (target_index == -1)
801 ERR("Unable to find target glyph\n");
802 return;
805 if (changeCount < 0)
807 /* merge glyphs */
808 for(i = target_index; i < chars && i >= 0; i+=write_dir)
810 if (pwLogClust[i] == target_glyph)
811 continue;
812 if(pwLogClust[i] == replacing_glyph)
813 pwLogClust[i] = target_glyph;
814 else
816 changed--;
817 if (changed >= changeCount)
819 replacing_glyph = pwLogClust[i];
820 pwLogClust[i] = target_glyph;
822 else
823 break;
827 /* renumber trailing indexes*/
828 for(i = target_index; i < chars && i >= 0; i+=write_dir)
830 if (pwLogClust[i] != target_glyph)
831 pwLogClust[i] += changeCount;
834 else
836 for(i = target_index; i < chars && i >= 0; i+=write_dir)
837 pwLogClust[i] += changeCount;
842 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 )
844 if (psc->GSUB_Table)
846 LoadedFeature *feature;
847 int lookup_index;
849 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
850 if (!feature)
851 return GSUB_E_NOFEATURE;
853 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
854 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
856 int i;
858 if (write_dir > 0)
859 i = 0;
860 else
861 i = *pcGlyphs-1;
862 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
863 while(i < *pcGlyphs && i >= 0)
865 INT nextIndex;
866 INT prevCount = *pcGlyphs;
868 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
869 if (*pcGlyphs != prevCount)
871 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
872 i = nextIndex;
874 else
875 i+=write_dir;
878 return *pcGlyphs;
880 return GSUB_E_NOFEATURE;
883 static VOID GPOS_apply_feature(ScriptCache *psc, LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, const SCRIPT_ANALYSIS *analysis, INT* piAdvance, LoadedFeature *feature, const WORD *glyphs, INT glyph_count, GOFFSET *pGoffset)
885 int i;
887 TRACE("%i lookups\n", feature->lookup_count);
888 for (i = 0; i < feature->lookup_count; i++)
890 int j;
891 for (j = 0; j < glyph_count; )
892 j = OpenType_apply_GPOS_lookup(psc, lpotm, lplogfont, analysis, piAdvance, feature->lookups[i], glyphs, j, glyph_count, pGoffset);
896 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
898 OPENTYPE_TAG tag;
899 HRESULT hr;
900 int count = 0;
902 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
904 return(SUCCEEDED(hr));
907 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
909 int i;
910 for (i = *pcGlyphs; i>=index; i--)
911 pwGlyphs[i+1] = pwGlyphs[i];
912 pwGlyphs[index] = glyph;
913 *pcGlyphs = *pcGlyphs+1;
914 if (write_dir < 0)
915 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
916 else
917 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
920 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)
922 CHAR *context_type;
923 int i,g;
924 WCHAR invalid = 0x25cc;
925 WORD invalid_glyph;
927 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
929 /* Mark invalid combinations */
930 for (i = 0; i < cChars; i++)
931 context_type[i] = lex(pwcChars[i]);
933 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
934 for (i = 1, g=1; i < cChars - 1; i++, g++)
936 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
938 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
939 g++;
943 HeapFree(GetProcessHeap(),0,context_type);
946 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
948 int i;
949 for (i=0; i < cChars; i++)
951 switch (pwcChars[i])
953 case 0x000A:
954 case 0x000D:
955 pwOutGlyphs[i] = psc->sfp.wgBlank;
956 break;
957 default:
958 if (pwcChars[i] < 0x1C)
959 pwOutGlyphs[i] = psc->sfp.wgDefault;
960 else
961 pwOutGlyphs[i] = psc->sfp.wgBlank;
966 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
968 if (i + delta < 0)
969 return 0;
970 if ( i+ delta >= cchLen)
971 return 0;
973 i += delta;
975 return chars[i];
978 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
980 if (i + delta < 0)
982 if (psa->fLinkBefore)
983 return jtR;
984 else
985 return jtU;
987 if ( i+ delta >= cchLen)
989 if (psa->fLinkAfter)
990 return jtL;
991 else
992 return jtU;
995 i += delta;
997 if (context_type[i] == jtT)
998 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
999 else
1000 return context_type[i];
1003 static inline BOOL right_join_causing(CHAR joining_type)
1005 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1008 static inline BOOL left_join_causing(CHAR joining_type)
1010 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1013 static inline BOOL word_break_causing(WCHAR chr)
1015 /* we are working within a string of characters already guareented to
1016 be within one script, Syriac, so we do not worry about any character
1017 other than the space character outside of that range */
1018 return (chr == 0 || chr == 0x20 );
1021 static int combining_lexical_Arabic(WCHAR c)
1023 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1025 switch(c)
1027 case 0x064B:
1028 case 0x064C:
1029 case 0x064E:
1030 case 0x064F:
1031 case 0x0652:
1032 case 0x0657:
1033 case 0x0658:
1034 case 0x06E1: return Arab_DIAC1;
1035 case 0x064D:
1036 case 0x0650:
1037 case 0x0656: return Arab_DIAC2;
1038 case 0x0651: return Arab_DIAC3;
1039 case 0x0610:
1040 case 0x0611:
1041 case 0x0612:
1042 case 0x0613:
1043 case 0x0614:
1044 case 0x0659:
1045 case 0x06D6:
1046 case 0x06DC:
1047 case 0x06DF:
1048 case 0x06E0:
1049 case 0x06E2:
1050 case 0x06E4:
1051 case 0x06E7:
1052 case 0x06E8:
1053 case 0x06EB:
1054 case 0x06EC: return Arab_DIAC4;
1055 case 0x06E3:
1056 case 0x06EA:
1057 case 0x06ED: return Arab_DIAC5;
1058 case 0x0670: return Arab_DIAC6;
1059 case 0x0653: return Arab_DIAC7;
1060 case 0x0655:
1061 case 0x0654: return Arab_DIAC8;
1062 default: return Arab_Norm;
1067 * ContextualShape_Arabic
1069 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1071 CHAR *context_type;
1072 INT *context_shape;
1073 INT dirR, dirL;
1074 int i;
1076 if (*pcGlyphs != cChars)
1078 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1079 return;
1082 if (!psa->fLogicalOrder && psa->fRTL)
1084 dirR = 1;
1085 dirL = -1;
1087 else
1089 dirR = -1;
1090 dirL = 1;
1093 load_ot_tables(hdc, psc);
1095 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1096 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1098 for (i = 0; i < cChars; i++)
1099 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1101 for (i = 0; i < cChars; i++)
1103 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1104 context_shape[i] = Xr;
1105 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1106 context_shape[i] = Xl;
1107 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)))
1108 context_shape[i] = Xm;
1109 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1110 context_shape[i] = Xr;
1111 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1112 context_shape[i] = Xl;
1113 else
1114 context_shape[i] = Xn;
1117 /* Contextual Shaping */
1118 i = 0;
1119 while(i < *pcGlyphs)
1121 BOOL shaped = FALSE;
1123 if (psc->GSUB_Table)
1125 INT nextIndex;
1126 INT prevCount = *pcGlyphs;
1127 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1128 if (nextIndex > GSUB_E_NOGLYPH)
1130 i = nextIndex;
1131 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1133 shaped = (nextIndex > GSUB_E_NOGLYPH);
1136 if (!shaped)
1138 if (context_shape[i] == Xn)
1140 WORD newGlyph = pwOutGlyphs[i];
1141 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1143 /* fall back to presentation form B */
1144 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1145 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1146 pwOutGlyphs[i] = newGlyph;
1149 i++;
1153 HeapFree(GetProcessHeap(),0,context_shape);
1154 HeapFree(GetProcessHeap(),0,context_type);
1156 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1159 static int combining_lexical_Hebrew(WCHAR c)
1161 enum {Hebr_Norm=0, Hebr_DIAC, Hebr_CANT1, Hebr_CANT2, Hebr_CANT3, Hebr_CANT4, Hebr_CANT5, Hebr_CANT6, Hebr_CANT7, Hebr_CANT8, Hebr_CANT9, Hebr_CANT10, Hebr_DAGESH, Hebr_DOTABV, Hebr_HOLAM, Hebr_METEG, Hebr_PATAH, Hebr_QAMATS, Hebr_RAFE, Hebr_SHINSIN};
1163 switch(c)
1165 case 0x05B0:
1166 case 0x05B1:
1167 case 0x05B2:
1168 case 0x05B3:
1169 case 0x05B4:
1170 case 0x05B5:
1171 case 0x05B6:
1172 case 0x05BB: return Hebr_DIAC;
1173 case 0x0599:
1174 case 0x05A1:
1175 case 0x05A9:
1176 case 0x05AE: return Hebr_CANT1;
1177 case 0x0597:
1178 case 0x05A8:
1179 case 0x05AC: return Hebr_CANT2;
1180 case 0x0592:
1181 case 0x0593:
1182 case 0x0594:
1183 case 0x0595:
1184 case 0x05A7:
1185 case 0x05AB: return Hebr_CANT3;
1186 case 0x0598:
1187 case 0x059C:
1188 case 0x059E:
1189 case 0x059F: return Hebr_CANT4;
1190 case 0x059D:
1191 case 0x05A0: return Hebr_CANT5;
1192 case 0x059B:
1193 case 0x05A5: return Hebr_CANT6;
1194 case 0x0591:
1195 case 0x05A3:
1196 case 0x05A6: return Hebr_CANT7;
1197 case 0x0596:
1198 case 0x05A4:
1199 case 0x05AA: return Hebr_CANT8;
1200 case 0x059A:
1201 case 0x05AD: return Hebr_CANT9;
1202 case 0x05AF: return Hebr_CANT10;
1203 case 0x05BC: return Hebr_DAGESH;
1204 case 0x05C4: return Hebr_DOTABV;
1205 case 0x05B9: return Hebr_HOLAM;
1206 case 0x05BD: return Hebr_METEG;
1207 case 0x05B7: return Hebr_PATAH;
1208 case 0x05B8: return Hebr_QAMATS;
1209 case 0x05BF: return Hebr_RAFE;
1210 case 0x05C1:
1211 case 0x05C2: return Hebr_SHINSIN;
1212 default: return Hebr_Norm;
1216 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1218 INT dirL;
1220 if (*pcGlyphs != cChars)
1222 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1223 return;
1226 if (!psa->fLogicalOrder && psa->fRTL)
1227 dirL = -1;
1228 else
1229 dirL = 1;
1231 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1235 * ContextualShape_Syriac
1238 static int combining_lexical_Syriac(WCHAR c)
1240 enum {Syriac_Norm=0, Syriac_DIAC1, Syriac_DIAC2, Syriac_DIAC3, Syriac_DIAC4, Syriac_DIAC5, Syriac_DIAC6, Syriac_DIAC7, Syriac_DIAC8, Syriac_DIAC9, Syriac_DIAC10, Syriac_DIAC11, Syriac_DIAC12, Syriac_DIAC13, Syriac_DIAC14, Syriac_DIAC15, Syriac_DIAC16, Syriac_DIAC17};
1242 switch(c)
1244 case 0x730:
1245 case 0x733:
1246 case 0x736:
1247 case 0x73A:
1248 case 0x73D: return Syriac_DIAC1;
1249 case 0x731:
1250 case 0x734:
1251 case 0x737:
1252 case 0x73B:
1253 case 0x73E: return Syriac_DIAC2;
1254 case 0x740:
1255 case 0x749:
1256 case 0x74A: return Syriac_DIAC3;
1257 case 0x732:
1258 case 0x735:
1259 case 0x73F: return Syriac_DIAC4;
1260 case 0x738:
1261 case 0x739:
1262 case 0x73C: return Syriac_DIAC5;
1263 case 0x741:
1264 case 0x30A: return Syriac_DIAC6;
1265 case 0x742:
1266 case 0x325: return Syriac_DIAC7;
1267 case 0x747:
1268 case 0x303: return Syriac_DIAC8;
1269 case 0x748:
1270 case 0x32D:
1271 case 0x32E:
1272 case 0x330:
1273 case 0x331: return Syriac_DIAC9;
1274 case 0x308: return Syriac_DIAC10;
1275 case 0x304: return Syriac_DIAC11;
1276 case 0x307: return Syriac_DIAC12;
1277 case 0x323: return Syriac_DIAC13;
1278 case 0x743: return Syriac_DIAC14;
1279 case 0x744: return Syriac_DIAC15;
1280 case 0x745: return Syriac_DIAC16;
1281 case 0x746: return Syriac_DIAC17;
1282 default: return Syriac_Norm;
1286 #define ALAPH 0x710
1287 #define DALATH 0x715
1288 #define RISH 0x72A
1290 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1292 CHAR *context_type;
1293 INT *context_shape;
1294 INT dirR, dirL;
1295 int i;
1297 if (*pcGlyphs != cChars)
1299 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1300 return;
1303 if (!psa->fLogicalOrder && psa->fRTL)
1305 dirR = 1;
1306 dirL = -1;
1308 else
1310 dirR = -1;
1311 dirL = 1;
1314 load_ot_tables(hdc, psc);
1316 if (!psc->GSUB_Table)
1317 return;
1319 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1320 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1322 for (i = 0; i < cChars; i++)
1323 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1325 for (i = 0; i < cChars; i++)
1327 if (pwcChars[i] == ALAPH)
1329 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1331 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1332 context_shape[i] = Afj;
1333 else if ( rchar != DALATH && rchar != RISH &&
1334 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1335 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1336 context_shape[i] = Afn;
1337 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1338 context_shape[i] = Afx;
1339 else
1340 context_shape[i] = Xn;
1342 else if (context_type[i] == jtR &&
1343 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1344 context_shape[i] = Xr;
1345 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1346 context_shape[i] = Xl;
1347 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)))
1348 context_shape[i] = Xm;
1349 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1350 context_shape[i] = Xr;
1351 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1352 context_shape[i] = Xl;
1353 else
1354 context_shape[i] = Xn;
1357 /* Contextual Shaping */
1358 i = 0;
1359 while(i < *pcGlyphs)
1361 INT nextIndex;
1362 INT prevCount = *pcGlyphs;
1363 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1364 if (nextIndex > GSUB_E_NOGLYPH)
1366 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1367 i = nextIndex;
1369 else
1370 i++;
1373 HeapFree(GetProcessHeap(),0,context_shape);
1374 HeapFree(GetProcessHeap(),0,context_type);
1376 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1379 static int combining_lexical_Thaana(WCHAR c)
1381 enum {Thaana_Norm=0, Thaana_FILI};
1383 switch(c)
1385 case 0x7A6:
1386 case 0x7A7:
1387 case 0x7A8:
1388 case 0x7A9:
1389 case 0x7AA:
1390 case 0x7AB:
1391 case 0x7AC:
1392 case 0x7AD:
1393 case 0x7AE:
1394 case 0x7AF: return Thaana_FILI;
1395 default: return Thaana_Norm;
1399 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1401 INT dirL;
1403 if (*pcGlyphs != cChars)
1405 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1406 return;
1409 if (!psa->fLogicalOrder && psa->fRTL)
1410 dirL = -1;
1411 else
1412 dirL = 1;
1414 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1418 * ContextualShape_Phags_pa
1421 #define phags_pa_CANDRABINDU 0xA873
1422 #define phags_pa_START 0xA840
1423 #define phags_pa_END 0xA87F
1425 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1427 INT *context_shape;
1428 INT dirR, dirL;
1429 int i;
1431 if (*pcGlyphs != cChars)
1433 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1434 return;
1437 if (!psa->fLogicalOrder && psa->fRTL)
1439 dirR = 1;
1440 dirL = -1;
1442 else
1444 dirR = -1;
1445 dirL = 1;
1448 load_ot_tables(hdc, psc);
1450 if (!psc->GSUB_Table)
1451 return;
1453 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1455 for (i = 0; i < cChars; i++)
1457 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1459 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1460 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1461 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1462 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1464 if (jrchar && jlchar)
1465 context_shape[i] = Xm;
1466 else if (jrchar)
1467 context_shape[i] = Xr;
1468 else if (jlchar)
1469 context_shape[i] = Xl;
1470 else
1471 context_shape[i] = Xn;
1473 else
1474 context_shape[i] = -1;
1477 /* Contextual Shaping */
1478 i = 0;
1479 while(i < *pcGlyphs)
1481 if (context_shape[i] >= 0)
1483 INT nextIndex;
1484 INT prevCount = *pcGlyphs;
1485 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1486 if (nextIndex > GSUB_E_NOGLYPH)
1488 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1489 i = nextIndex;
1491 else
1492 i++;
1494 else
1495 i++;
1498 HeapFree(GetProcessHeap(),0,context_shape);
1501 static int combining_lexical_Thai(WCHAR c)
1503 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1505 switch(c)
1507 case 0xE31:
1508 case 0xE34:
1509 case 0xE35:
1510 case 0xE36:
1511 case 0xE37: return Thai_ABOVE1;
1512 case 0xE47:
1513 case 0xE4D: return Thai_ABOVE2;
1514 case 0xE48:
1515 case 0xE49:
1516 case 0xE4A:
1517 case 0xE4B: return Thai_ABOVE3;
1518 case 0xE4C:
1519 case 0xE4E: return Thai_ABOVE4;
1520 case 0xE38:
1521 case 0xE39: return Thai_BELOW1;
1522 case 0xE3A: return Thai_BELOW2;
1523 case 0xE33: return Thai_AM;
1524 default: return Thai_Norm;
1528 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1530 INT dirL;
1532 if (*pcGlyphs != cChars)
1534 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1535 return;
1538 if (!psa->fLogicalOrder && psa->fRTL)
1539 dirL = -1;
1540 else
1541 dirL = 1;
1543 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1546 static int combining_lexical_Lao(WCHAR c)
1548 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1550 switch(c)
1552 case 0xEB1:
1553 case 0xEB4:
1554 case 0xEB5:
1555 case 0xEB6:
1556 case 0xEB7:
1557 case 0xEBB:
1558 case 0xECD: return Lao_ABOVE1;
1559 case 0xEC8:
1560 case 0xEC9:
1561 case 0xECA:
1562 case 0xECB:
1563 case 0xECC: return Lao_ABOVE2;
1564 case 0xEBC: return Lao_BELOW1;
1565 case 0xEB8:
1566 case 0xEB9: return Lao_BELOW2;
1567 case 0xEB3: return Lao_AM;
1568 default: return Lao_Norm;
1572 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1574 INT dirL;
1576 if (*pcGlyphs != cChars)
1578 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1579 return;
1582 if (!psa->fLogicalOrder && psa->fRTL)
1583 dirL = -1;
1584 else
1585 dirL = 1;
1587 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1590 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1592 int i;
1594 /* Replace */
1595 pwOutChars[cWalk] = replacements[0];
1596 cWalk=cWalk+1;
1598 /* Insert */
1599 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1601 int j;
1602 for (j = *pcChars; j > cWalk; j--)
1603 pwOutChars[j] = pwOutChars[j-1];
1604 *pcChars= *pcChars+1;
1605 pwOutChars[cWalk] = replacements[i];
1606 cWalk = cWalk+1;
1610 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1612 int i;
1613 int cWalk;
1615 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1617 for (i = 0; vowels[i].base != 0x0; i++)
1619 if (pwOutChars[cWalk] == vowels[i].base)
1621 int o = 0;
1622 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1623 if (vowels[i].parts[1]) { cWalk++; o++; }
1624 if (vowels[i].parts[2]) { cWalk++; o++; }
1625 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1626 break;
1632 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1634 int i;
1635 int offset = 0;
1636 int cWalk;
1638 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1640 for (i = 0; consonants[i].output!= 0x0; i++)
1642 int j;
1643 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1644 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1645 break;
1647 if (consonants[i].parts[j]==0x0) /* matched all */
1649 int k;
1650 j--;
1651 pwOutChars[cWalk] = consonants[i].output;
1652 for(k = cWalk+1; k < *pcChars - j; k++)
1653 pwOutChars[k] = pwOutChars[k+j];
1654 *pcChars = *pcChars - j;
1655 for (k = j ; k > 0; k--)
1656 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1657 offset += j;
1658 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1659 pwLogClust[k]--;
1660 break;
1663 cWalk++;
1667 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1669 if (s->ralf >= 0)
1671 int j;
1672 WORD Ra = pwChar[s->start];
1673 WORD H = pwChar[s->start+1];
1675 TRACE("Doing reorder of Ra to %i\n",s->base);
1676 for (j = s->start; j < s->base-1; j++)
1677 pwChar[j] = pwChar[j+2];
1678 pwChar[s->base-1] = Ra;
1679 pwChar[s->base] = H;
1681 s->ralf = s->base-1;
1682 s->base -= 2;
1686 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1688 if (s->ralf >= 0)
1690 int j,loc;
1691 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1692 WORD Ra = pwChar[s->start];
1693 WORD H = pwChar[s->start+1];
1694 for (loc = s->end; loc > stop; loc--)
1695 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1696 break;
1698 TRACE("Doing reorder of Ra to %i\n",loc);
1699 for (j = s->start; j < loc-1; j++)
1700 pwChar[j] = pwChar[j+2];
1701 pwChar[loc-1] = Ra;
1702 pwChar[loc] = H;
1704 s->ralf = loc-1;
1705 s->base -= 2;
1706 if (s->blwf >= 0) s->blwf -= 2;
1707 if (s->pref >= 0) s->pref -= 2;
1711 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1713 if (s->ralf >= 0)
1715 int j;
1716 WORD Ra = pwChar[s->start];
1717 WORD H = pwChar[s->start+1];
1719 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1720 for (j = s->start; j < s->end-1; j++)
1721 pwChar[j] = pwChar[j+2];
1722 pwChar[s->end-1] = Ra;
1723 pwChar[s->end] = H;
1725 s->ralf = s->end-1;
1726 s->base -= 2;
1727 if (s->blwf >= 0) s->blwf -= 2;
1728 if (s->pref >= 0) s->pref -= 2;
1732 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1734 int i;
1736 /* reorder Matras */
1737 if (s->end > s->base)
1739 for (i = 1; i <= s->end-s->base; i++)
1741 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1743 int j;
1744 WCHAR c = pwChar[s->base+i];
1745 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1746 for (j = s->base+i; j > s->base; j--)
1747 pwChar[j] = pwChar[j-1];
1748 pwChar[s->base] = c;
1750 if (s->ralf >= s->base) s->ralf++;
1751 if (s->blwf >= s->base) s->blwf++;
1752 if (s->pref >= s->base) s->pref++;
1753 s->base ++;
1759 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1761 int i;
1763 /* reorder Matras */
1764 if (s->end > s->base)
1766 for (i = 1; i <= s->end-s->base; i++)
1768 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1770 int j;
1771 WCHAR c = pwChar[s->base+i];
1772 TRACE("Doing reorder of %x to %i\n",c,s->start);
1773 for (j = s->base+i; j > s->start; j--)
1774 pwChar[j] = pwChar[j-1];
1775 pwChar[s->start] = c;
1777 if (s->ralf >= 0) s->ralf++;
1778 if (s->blwf >= 0) s->blwf++;
1779 if (s->pref >= 0) s->pref++;
1780 s->base ++;
1786 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1788 if (s->blwf >= 0 && g->blwf > g->base)
1790 int j,loc;
1791 int g_offset;
1792 for (loc = s->end; loc > s->blwf; loc--)
1793 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1794 break;
1796 g_offset = (loc - s->blwf) - 1;
1798 if (loc != s->blwf)
1800 WORD blwf = glyphs[g->blwf];
1801 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1802 /* do not care about the pwChar array anymore, just the glyphs */
1803 for (j = 0; j < g_offset; j++)
1804 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1805 glyphs[g->blwf + g_offset] = blwf;
1810 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1812 int i;
1814 /* reorder previously moved Matras to correct position*/
1815 for (i = s->start; i < s->base; i++)
1817 if (lexical(pwChar[i]) == lex_Matra_pre)
1819 int j;
1820 int g_start = g->start + i - s->start;
1821 if (g_start < g->base -1 )
1823 WCHAR og = glyphs[g_start];
1824 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1825 for (j = g_start; j < g->base-1; j++)
1826 glyphs[j] = glyphs[j+1];
1827 glyphs[g->base-1] = og;
1833 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1835 if (s->pref >= 0 && g->pref > g->base)
1837 int j;
1838 WCHAR og = glyphs[g->pref];
1839 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1840 for (j = g->pref; j > g->base; j--)
1841 glyphs[j] = glyphs[j-1];
1842 glyphs[g->base] = og;
1846 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1848 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1849 if (s->start == s->base && s->base == s->end) return;
1850 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1852 Reorder_Ra_follows_base(pwChar, s, lexical);
1853 Reorder_Matra_precede_base(pwChar, s, lexical);
1856 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1858 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1859 if (s->start == s->base && s->base == s->end) return;
1860 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1862 Reorder_Ra_follows_matra(pwChar, s, lexical);
1863 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1866 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1868 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1869 if (s->start == s->base && s->base == s->end) return;
1870 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1872 Reorder_Ra_follows_base(pwChar, s, lexical);
1873 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1876 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1878 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1879 if (s->start == s->base && s->base == s->end) return;
1880 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1882 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1883 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1886 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1888 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1889 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1890 if (s->start == s->base && s->base == s->end) return;
1891 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1893 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1896 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1898 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1899 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1900 if (s->start == s->base && s->base == s->end) return;
1901 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1903 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1904 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1908 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1910 if (shift == 0)
1911 return;
1913 if (glyph_index->start > index)
1914 glyph_index->start += shift;
1915 if (glyph_index->base > index)
1916 glyph_index->base+= shift;
1917 if (glyph_index->end > index)
1918 glyph_index->end+= shift;
1919 if (glyph_index->ralf > index)
1920 glyph_index->ralf+= shift;
1921 if (glyph_index->blwf > index)
1922 glyph_index->blwf+= shift;
1923 if (glyph_index->pref > index)
1924 glyph_index->pref+= shift;
1927 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 )
1929 int index = glyph_index->start;
1931 if (!feature)
1932 return;
1934 while(index <= glyph_index->end)
1936 INT nextIndex;
1937 INT prevCount = *pcGlyphs;
1938 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1939 if (nextIndex > GSUB_E_NOGLYPH)
1941 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1942 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1943 index = nextIndex;
1945 else
1946 index++;
1950 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1952 int i = 0;
1953 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)))))
1954 i++;
1955 if (index + i <= end-1)
1956 return index + i;
1957 else
1958 return -1;
1961 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)
1963 INT index, nextIndex;
1964 INT count,g_offset;
1966 count = syllable->base - syllable->start;
1968 g_offset = 0;
1969 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1970 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1972 INT prevCount = *pcGlyphs;
1973 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1974 if (nextIndex > GSUB_E_NOGLYPH)
1976 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1977 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1978 g_offset += (*pcGlyphs - prevCount);
1981 index+=2;
1982 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1986 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)
1988 INT nextIndex;
1989 INT prevCount = *pcGlyphs;
1991 if (syllable->ralf >= 0)
1993 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1994 if (nextIndex > GSUB_E_NOGLYPH)
1996 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1997 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2002 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2004 int i = 0;
2005 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2006 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2007 is_consonant(lexical(pwChars[index+i+1])))))
2008 i++;
2009 if (index + i <= end-1)
2010 return index+i;
2011 else
2012 return -1;
2015 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)
2017 INT index, nextIndex;
2018 INT count, g_offset=0;
2019 INT ralf = syllable->ralf;
2021 count = syllable->end - syllable->base;
2023 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2025 while (index >= 0)
2027 INT prevCount = *pcGlyphs;
2028 if (ralf >=0 && ralf < index)
2030 g_offset--;
2031 ralf = -1;
2034 if (!modern)
2036 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2037 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2038 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2041 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2042 if (nextIndex > GSUB_E_NOGLYPH)
2044 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2045 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2046 g_offset += (*pcGlyphs - prevCount);
2048 else if (!modern)
2050 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2051 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2052 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2055 index+=2;
2056 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2060 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)
2062 int c;
2063 int overall_shift = 0;
2064 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2065 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2066 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2067 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2068 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2069 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2070 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2071 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2072 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2073 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2074 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2075 IndicSyllable glyph_indexs;
2077 for (c = 0; c < syllable_count; c++)
2079 int old_end;
2080 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2081 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2082 old_end = glyph_indexs.end;
2084 if (locl)
2086 TRACE("applying feature locl\n");
2087 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2089 if (nukt)
2091 TRACE("applying feature nukt\n");
2092 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2094 if (akhn)
2096 TRACE("applying feature akhn\n");
2097 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2100 if (rphf)
2101 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2102 if (rkrf)
2104 TRACE("applying feature rkrf\n");
2105 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2107 if (pref)
2108 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2109 if (blwf)
2111 if (!modern)
2112 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2114 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2117 if (half)
2118 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2119 if (pstf)
2121 TRACE("applying feature pstf\n");
2122 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2124 if (vatu)
2126 TRACE("applying feature vatu\n");
2127 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2129 if (cjct)
2131 TRACE("applying feature cjct\n");
2132 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2135 if (second_reorder)
2136 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2138 overall_shift += glyph_indexs.end - old_end;
2142 static inline int unicode_lex(WCHAR c)
2144 int type;
2146 if (!c) return lex_Generic;
2147 if (c == 0x200D) return lex_ZWJ;
2148 if (c == 0x200C) return lex_ZWNJ;
2149 if (c == 0x00A0) return lex_NBSP;
2151 type = get_table_entry( indic_syllabic_table, c );
2153 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2155 switch( type )
2157 case 0x0d07: /* Unknown */
2158 case 0x0e07: /* Unknwon */
2159 default: return lex_Generic;
2160 case 0x0001:
2161 case 0x0002:
2162 case 0x0011:
2163 case 0x0012:
2164 case 0x0013:
2165 case 0x0014: return lex_Modifier;
2166 case 0x0003:
2167 case 0x0009:
2168 case 0x000a:
2169 case 0x000b:
2170 case 0x000d:
2171 case 0x000e:
2172 case 0x000f:
2173 case 0x0010: return lex_Consonant;
2174 case 0x0004: return lex_Nukta;
2175 case 0x0005: return lex_Halant;
2176 case 0x0006:
2177 case 0x0008: return lex_Vowel;
2178 case 0x0007:
2179 case 0x0107: return lex_Matra_post;
2180 case 0x0207:
2181 case 0x0307: return lex_Matra_pre;
2182 case 0x0807:
2183 case 0x0907:
2184 case 0x0a07:
2185 case 0x0b07:
2186 case 0x0c07:
2187 case 0x0407: return lex_Composed_Vowel;
2188 case 0x0507: return lex_Matra_above;
2189 case 0x0607: return lex_Matra_below;
2190 case 0x000c:
2191 case 0x0015: return lex_Ra;
2195 static int sinhala_lex(WCHAR c)
2197 switch (c)
2199 case 0x0DDA:
2200 case 0x0DDD:
2201 case 0x0DDC:
2202 case 0x0DDE: return lex_Matra_post;
2203 default:
2204 return unicode_lex(c);
2208 static const VowelComponents Sinhala_vowels[] = {
2209 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2210 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2211 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2212 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2213 {0x0000, {0x0000,0x0000,0x0}}};
2215 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2217 int cCount = cChars;
2218 int i;
2219 WCHAR *input;
2220 IndicSyllable *syllables = NULL;
2221 int syllable_count = 0;
2223 if (*pcGlyphs != cChars)
2225 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2226 return;
2229 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2231 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2233 /* Step 1: Decompose multi part vowels */
2234 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2236 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2238 /* Step 2: Reorder within Syllables */
2239 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2240 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2242 /* Step 3: Strip dangling joiners */
2243 for (i = 0; i < cCount; i++)
2245 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2246 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2247 input[i] = 0x0020;
2250 /* Step 4: Base Form application to syllables */
2251 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2252 *pcGlyphs = cCount;
2253 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2255 HeapFree(GetProcessHeap(),0,input);
2256 HeapFree(GetProcessHeap(),0,syllables);
2259 static int devanagari_lex(WCHAR c)
2261 switch (c)
2263 case 0x0930: return lex_Ra;
2264 default:
2265 return unicode_lex(c);
2269 static const ConsonantComponents Devanagari_consonants[] ={
2270 {{0x0928, 0x093C, 0x00000}, 0x0929},
2271 {{0x0930, 0x093C, 0x00000}, 0x0931},
2272 {{0x0933, 0x093C, 0x00000}, 0x0934},
2273 {{0x0915, 0x093C, 0x00000}, 0x0958},
2274 {{0x0916, 0x093C, 0x00000}, 0x0959},
2275 {{0x0917, 0x093C, 0x00000}, 0x095A},
2276 {{0x091C, 0x093C, 0x00000}, 0x095B},
2277 {{0x0921, 0x093C, 0x00000}, 0x095C},
2278 {{0x0922, 0x093C, 0x00000}, 0x095D},
2279 {{0x092B, 0x093C, 0x00000}, 0x095E},
2280 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2282 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2284 int cCount = cChars;
2285 WCHAR *input;
2286 IndicSyllable *syllables = NULL;
2287 int syllable_count = 0;
2288 BOOL modern = get_GSUB_Indic2(psa, psc);
2290 if (*pcGlyphs != cChars)
2292 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2293 return;
2296 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2297 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2299 /* Step 1: Compose Consonant and Nukta */
2300 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2301 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2303 /* Step 2: Reorder within Syllables */
2304 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2305 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2306 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2307 *pcGlyphs = cCount;
2309 /* Step 3: Base Form application to syllables */
2310 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2312 HeapFree(GetProcessHeap(),0,input);
2313 HeapFree(GetProcessHeap(),0,syllables);
2316 static int bengali_lex(WCHAR c)
2318 switch (c)
2320 case 0x09B0: return lex_Ra;
2321 default:
2322 return unicode_lex(c);
2326 static const VowelComponents Bengali_vowels[] = {
2327 {0x09CB, {0x09C7,0x09BE,0x0000}},
2328 {0x09CC, {0x09C7,0x09D7,0x0000}},
2329 {0x0000, {0x0000,0x0000,0x0000}}};
2331 static const ConsonantComponents Bengali_consonants[] = {
2332 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2333 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2334 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2335 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2336 {{0x0000,0x0000,0x0000}, 0x0000}};
2338 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2340 int cCount = cChars;
2341 WCHAR *input;
2342 IndicSyllable *syllables = NULL;
2343 int syllable_count = 0;
2344 BOOL modern = get_GSUB_Indic2(psa, psc);
2346 if (*pcGlyphs != cChars)
2348 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2349 return;
2352 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2353 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2355 /* Step 1: Decompose Vowels and Compose Consonants */
2356 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2357 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2358 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2360 /* Step 2: Reorder within Syllables */
2361 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2362 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2363 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2364 *pcGlyphs = cCount;
2366 /* Step 3: Initial form is only applied to the beginning of words */
2367 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2369 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2371 int index = cCount;
2372 int gCount = 1;
2373 if (index > 0) index++;
2375 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2379 /* Step 4: Base Form application to syllables */
2380 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2382 HeapFree(GetProcessHeap(),0,input);
2383 HeapFree(GetProcessHeap(),0,syllables);
2386 static int gurmukhi_lex(WCHAR c)
2388 if (c == 0x0A71)
2389 return lex_Modifier;
2390 else
2391 return unicode_lex(c);
2394 static const ConsonantComponents Gurmukhi_consonants[] = {
2395 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2396 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2397 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2398 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2399 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2400 {{0x0000,0x0000,0x0000}, 0x0000}};
2402 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2404 int cCount = cChars;
2405 WCHAR *input;
2406 IndicSyllable *syllables = NULL;
2407 int syllable_count = 0;
2408 BOOL modern = get_GSUB_Indic2(psa, psc);
2410 if (*pcGlyphs != cChars)
2412 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2413 return;
2416 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2417 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2419 /* Step 1: Compose Consonants */
2420 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2421 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2423 /* Step 2: Reorder within Syllables */
2424 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2425 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2426 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2427 *pcGlyphs = cCount;
2429 /* Step 3: Base Form application to syllables */
2430 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2432 HeapFree(GetProcessHeap(),0,input);
2433 HeapFree(GetProcessHeap(),0,syllables);
2436 static int gujarati_lex(WCHAR c)
2438 switch (c)
2440 case 0x0AB0: return lex_Ra;
2441 default:
2442 return unicode_lex(c);
2446 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2448 int cCount = cChars;
2449 WCHAR *input;
2450 IndicSyllable *syllables = NULL;
2451 int syllable_count = 0;
2452 BOOL modern = get_GSUB_Indic2(psa, psc);
2454 if (*pcGlyphs != cChars)
2456 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2457 return;
2460 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2461 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2463 /* Step 1: Reorder within Syllables */
2464 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2465 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2466 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2467 *pcGlyphs = cCount;
2469 /* Step 2: Base Form application to syllables */
2470 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2472 HeapFree(GetProcessHeap(),0,input);
2473 HeapFree(GetProcessHeap(),0,syllables);
2476 static int oriya_lex(WCHAR c)
2478 switch (c)
2480 case 0x0B30: return lex_Ra;
2481 default:
2482 return unicode_lex(c);
2486 static const VowelComponents Oriya_vowels[] = {
2487 {0x0B48, {0x0B47,0x0B56,0x0000}},
2488 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2489 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2490 {0x0000, {0x0000,0x0000,0x0000}}};
2492 static const ConsonantComponents Oriya_consonants[] = {
2493 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2494 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2495 {{0x0000,0x0000,0x0000}, 0x0000}};
2497 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2499 int cCount = cChars;
2500 WCHAR *input;
2501 IndicSyllable *syllables = NULL;
2502 int syllable_count = 0;
2503 BOOL modern = get_GSUB_Indic2(psa, psc);
2505 if (*pcGlyphs != cChars)
2507 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2508 return;
2511 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2512 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2514 /* Step 1: Decompose Vowels and Compose Consonants */
2515 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2516 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2517 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2519 /* Step 2: Reorder within Syllables */
2520 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2521 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2522 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2523 *pcGlyphs = cCount;
2525 /* Step 3: Base Form application to syllables */
2526 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2528 HeapFree(GetProcessHeap(),0,input);
2529 HeapFree(GetProcessHeap(),0,syllables);
2532 static int tamil_lex(WCHAR c)
2534 return unicode_lex(c);
2537 static const VowelComponents Tamil_vowels[] = {
2538 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2539 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2540 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2541 {0x0000, {0x0000,0x0000,0x0000}}};
2543 static const ConsonantComponents Tamil_consonants[] = {
2544 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2545 {{0x0000,0x0000,0x0000}, 0x0000}};
2547 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2549 int cCount = cChars;
2550 WCHAR *input;
2551 IndicSyllable *syllables = NULL;
2552 int syllable_count = 0;
2553 BOOL modern = get_GSUB_Indic2(psa, psc);
2555 if (*pcGlyphs != cChars)
2557 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2558 return;
2561 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2562 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2564 /* Step 1: Decompose Vowels and Compose Consonants */
2565 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2566 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2567 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2569 /* Step 2: Reorder within Syllables */
2570 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2571 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2572 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2573 *pcGlyphs = cCount;
2575 /* Step 3: Base Form application to syllables */
2576 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2578 HeapFree(GetProcessHeap(),0,input);
2579 HeapFree(GetProcessHeap(),0,syllables);
2582 static int telugu_lex(WCHAR c)
2584 switch (c)
2586 case 0x0C43:
2587 case 0x0C44: return lex_Modifier;
2588 default:
2589 return unicode_lex(c);
2593 static const VowelComponents Telugu_vowels[] = {
2594 {0x0C48, {0x0C46,0x0C56,0x0000}},
2595 {0x0000, {0x0000,0x0000,0x0000}}};
2597 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2599 int cCount = cChars;
2600 WCHAR *input;
2601 IndicSyllable *syllables = NULL;
2602 int syllable_count = 0;
2603 BOOL modern = get_GSUB_Indic2(psa, psc);
2605 if (*pcGlyphs != cChars)
2607 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2608 return;
2611 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2612 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2614 /* Step 1: Decompose Vowels */
2615 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2616 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2618 /* Step 2: Reorder within Syllables */
2619 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2620 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2621 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2622 *pcGlyphs = cCount;
2624 /* Step 3: Base Form application to syllables */
2625 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2627 HeapFree(GetProcessHeap(),0,input);
2628 HeapFree(GetProcessHeap(),0,syllables);
2631 static int kannada_lex(WCHAR c)
2633 switch (c)
2635 case 0x0CB0: return lex_Ra;
2636 default:
2637 return unicode_lex(c);
2641 static const VowelComponents Kannada_vowels[] = {
2642 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2643 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2644 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2645 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2646 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2647 {0x0000, {0x0000,0x0000,0x0000}}};
2649 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2651 int cCount = cChars;
2652 WCHAR *input;
2653 IndicSyllable *syllables = NULL;
2654 int syllable_count = 0;
2655 BOOL modern = get_GSUB_Indic2(psa, psc);
2657 if (*pcGlyphs != cChars)
2659 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2660 return;
2663 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2664 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2666 /* Step 1: Decompose Vowels */
2667 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2668 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2670 /* Step 2: Reorder within Syllables */
2671 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2672 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2673 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2674 *pcGlyphs = cCount;
2676 /* Step 3: Base Form application to syllables */
2677 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2679 HeapFree(GetProcessHeap(),0,input);
2680 HeapFree(GetProcessHeap(),0,syllables);
2683 static int malayalam_lex(WCHAR c)
2685 return unicode_lex(c);
2688 static const VowelComponents Malayalam_vowels[] = {
2689 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2690 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2691 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2692 {0x0000, {0x0000,0x0000,0x0000}}};
2694 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2696 int cCount = cChars;
2697 WCHAR *input;
2698 IndicSyllable *syllables = NULL;
2699 int syllable_count = 0;
2700 BOOL modern = get_GSUB_Indic2(psa, psc);
2702 if (*pcGlyphs != cChars)
2704 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2705 return;
2708 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2709 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2711 /* Step 1: Decompose Vowels */
2712 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2713 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2715 /* Step 2: Reorder within Syllables */
2716 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2717 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2718 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2719 *pcGlyphs = cCount;
2721 /* Step 3: Base Form application to syllables */
2722 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2724 HeapFree(GetProcessHeap(),0,input);
2725 HeapFree(GetProcessHeap(),0,syllables);
2728 static int khmer_lex(WCHAR c)
2730 return unicode_lex(c);
2733 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2735 int cCount = cChars;
2736 WCHAR *input;
2737 IndicSyllable *syllables = NULL;
2738 int syllable_count = 0;
2740 if (*pcGlyphs != cChars)
2742 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2743 return;
2746 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2747 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2749 /* Step 1: Reorder within Syllables */
2750 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2751 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2752 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2753 *pcGlyphs = cCount;
2755 /* Step 2: Base Form application to syllables */
2756 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2758 HeapFree(GetProcessHeap(),0,input);
2759 HeapFree(GetProcessHeap(),0,syllables);
2762 static inline BOOL mongolian_wordbreak(WCHAR chr)
2764 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2767 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2769 INT *context_shape;
2770 INT dirL;
2771 int i;
2773 if (*pcGlyphs != cChars)
2775 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2776 return;
2779 if (!psa->fLogicalOrder && psa->fRTL)
2780 dirL = -1;
2781 else
2782 dirL = 1;
2784 if (!psc->GSUB_Table)
2785 return;
2787 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2789 for (i = 0; i < cChars; i++)
2791 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2793 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2794 context_shape[i] = Xn;
2795 else
2796 context_shape[i] = Xl;
2798 else
2800 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2801 context_shape[i] = Xr;
2802 else
2803 context_shape[i] = Xm;
2807 /* Contextual Shaping */
2808 i = 0;
2809 while(i < *pcGlyphs)
2811 INT nextIndex;
2812 INT prevCount = *pcGlyphs;
2813 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2814 if (nextIndex > GSUB_E_NOGLYPH)
2816 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2817 i = nextIndex;
2819 else
2820 i++;
2823 HeapFree(GetProcessHeap(),0,context_shape);
2826 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
2828 int i,k;
2830 for (i = 0; i < cGlyphs; i++)
2832 int char_index[20];
2833 int char_count = 0;
2835 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2836 if (k>=0)
2838 for (; k < cChars && pwLogClust[k] == i; k++)
2839 char_index[char_count++] = k;
2842 if (char_count == 0)
2843 continue;
2845 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2847 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2848 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2850 else
2851 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2854 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2855 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2858 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2860 int i;
2862 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2864 for (i = 0; i < cGlyphs; i++)
2865 if (pGlyphProp[i].sva.fZeroWidth)
2866 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2869 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2871 int i;
2872 for (i = 0; i < cGlyphs; i++)
2874 pGlyphProp[i].sva.fClusterStart = 1;
2875 pGlyphProp[i].sva.fDiacritic = 0;
2876 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2878 if (pwGlyphs[i] == psc->sfp.wgDefault)
2879 pGlyphProp[i].sva.fZeroWidth = 0;
2880 else
2881 pGlyphProp[i].sva.fZeroWidth = 1;
2885 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 )
2887 int i,k;
2888 int initGlyph, finaGlyph;
2889 INT dirR, dirL;
2890 BYTE *spaces;
2892 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2893 memset(spaces,0,cGlyphs);
2895 if (!psa->fLogicalOrder && psa->fRTL)
2897 initGlyph = cGlyphs-1;
2898 finaGlyph = 0;
2899 dirR = 1;
2900 dirL = -1;
2902 else
2904 initGlyph = 0;
2905 finaGlyph = cGlyphs-1;
2906 dirR = -1;
2907 dirL = 1;
2910 for (i = 0; i < cGlyphs; i++)
2912 for (k = 0; k < cChars; k++)
2913 if (pwLogClust[k] == i)
2915 if (pwcChars[k] == 0x0020)
2916 spaces[i] = 1;
2920 for (i = 0; i < cGlyphs; i++)
2922 int char_index[20];
2923 int char_count = 0;
2924 BOOL isInit, isFinal;
2926 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2927 if (k>=0)
2929 for (; k < cChars && pwLogClust[k] == i; k++)
2930 char_index[char_count++] = k;
2933 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2934 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2936 if (char_count == 0)
2937 continue;
2939 if (char_count == 1)
2941 if (pwcChars[char_index[0]] == 0x0020) /* space */
2943 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2944 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2946 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2947 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2948 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2950 if (!isInit && !isFinal)
2951 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2952 else if (isInit)
2953 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2954 else
2955 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2957 else if (!isInit)
2959 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2960 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2961 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2962 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2963 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2964 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2965 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2966 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2967 else
2968 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2970 else if (!isInit && !isFinal)
2971 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2972 else
2973 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2975 else if (char_count == 2)
2977 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2978 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2979 else if (!isInit)
2980 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2981 else
2982 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2984 else if (!isInit && !isFinal)
2985 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2986 else
2987 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2990 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2991 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2992 HeapFree(GetProcessHeap(),0,spaces);
2995 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 )
2997 int i,k;
2999 for (i = 0; i < cGlyphs; i++)
3001 int char_index[20];
3002 int char_count = 0;
3004 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3005 if (k>=0)
3007 for (; k < cChars && pwLogClust[k] == i; k++)
3008 char_index[char_count++] = k;
3011 if (char_count == 0)
3012 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3013 else
3015 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3016 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3017 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3021 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3022 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3025 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 )
3027 int i;
3028 int finaGlyph;
3029 INT dirL;
3031 if (!psa->fLogicalOrder && psa->fRTL)
3033 finaGlyph = 0;
3034 dirL = -1;
3036 else
3038 finaGlyph = cGlyphs-1;
3039 dirL = 1;
3042 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3044 for (i = 0; i < cGlyphs; i++)
3046 int k;
3047 int char_index[20];
3048 int char_count = 0;
3050 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3051 if (k>=0)
3053 for (; k < cChars && pwLogClust[k] == i; k++)
3054 char_index[char_count++] = k;
3057 if (i == finaGlyph)
3058 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3059 else
3060 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3062 if (char_count == 0)
3063 continue;
3065 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3066 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3068 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3069 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3070 pGlyphProp[i].sva.fClusterStart = 0;
3073 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3075 /* Do not allow justification between marks and their base */
3076 for (i = 0; i < cGlyphs; i++)
3078 if (!pGlyphProp[i].sva.fClusterStart)
3079 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3083 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)
3085 int i,k;
3087 for (i = 0; i < cGlyphs; i++)
3089 int char_index[20];
3090 int char_count = 0;
3092 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3093 if (k>=0)
3095 for (; k < cChars && pwLogClust[k] == i; k++)
3096 char_index[char_count++] = k;
3099 if (char_count == 0)
3100 continue;
3102 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3104 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3105 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3107 else
3108 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3110 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3111 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3114 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)
3116 int i,k;
3118 for (i = 0; i < cGlyphs; i++)
3120 int char_index[20];
3121 int char_count = 0;
3123 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3124 if (k>=0)
3126 for (; k < cChars && pwLogClust[k] == i; k++)
3127 char_index[char_count++] = k;
3130 if (char_count == 0)
3131 continue;
3133 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3135 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3136 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3138 else
3139 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3141 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3142 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3144 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3145 for (i = 0; i < cGlyphs; i++)
3147 if (!pGlyphProp[i].sva.fClusterStart)
3149 pGlyphProp[i].sva.fDiacritic = 0;
3150 pGlyphProp[i].sva.fZeroWidth = 0;
3155 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)
3157 int i,k;
3159 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3160 for (i = 0; i < cGlyphs; i++)
3162 int char_index[20];
3163 int char_count = 0;
3165 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3166 if (k>=0)
3168 for (; k < cChars && pwLogClust[k] == i; k++)
3169 char_index[char_count++] = k;
3172 if (override_gsub)
3174 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3175 pGlyphProp[i].sva.fDiacritic = FALSE;
3176 pGlyphProp[i].sva.fZeroWidth = FALSE;
3179 if (char_count == 0)
3181 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3182 continue;
3185 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3187 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3188 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3190 else
3191 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3193 pGlyphProp[i].sva.fClusterStart = 0;
3194 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3195 switch (lexical(pwcChars[char_index[k]]))
3197 case lex_Matra_pre:
3198 case lex_Matra_post:
3199 case lex_Matra_above:
3200 case lex_Matra_below:
3201 case lex_Modifier:
3202 case lex_Halant:
3203 break;
3204 case lex_ZWJ:
3205 case lex_ZWNJ:
3206 /* check for dangling joiners */
3207 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3208 pGlyphProp[i].sva.fClusterStart = 1;
3209 else
3210 k = char_count;
3211 break;
3212 default:
3213 pGlyphProp[i].sva.fClusterStart = 1;
3214 break;
3218 if (use_syllables)
3220 IndicSyllable *syllables = NULL;
3221 int syllable_count = 0;
3222 BOOL modern = get_GSUB_Indic2(psa, psc);
3224 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3226 for (i = 0; i < syllable_count; i++)
3228 int j;
3229 WORD g = pwLogClust[syllables[i].start];
3230 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3232 if (pwLogClust[j] != g)
3234 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3235 pwLogClust[j] = g;
3240 HeapFree(GetProcessHeap(), 0, syllables);
3243 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3246 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 )
3248 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3251 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 )
3253 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3256 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 )
3258 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3261 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 )
3263 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3266 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 )
3268 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3271 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 )
3273 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3276 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 )
3278 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3281 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 )
3283 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3286 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 )
3288 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3291 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 )
3293 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3296 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 )
3298 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3301 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)
3303 load_ot_tables(hdc, psc);
3305 if (ShapingData[psa->eScript].charGlyphPropProc)
3306 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3307 else
3308 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3311 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3313 load_ot_tables(hdc, psc);
3315 if (ShapingData[psa->eScript].contextProc)
3316 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3319 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)
3321 int i;
3322 INT dirL;
3324 if (!rpRangeProperties)
3325 return;
3327 load_ot_tables(hdc, psc);
3329 if (!psc->GSUB_Table)
3330 return;
3332 if (!psa->fLogicalOrder && psa->fRTL)
3333 dirL = -1;
3334 else
3335 dirL = 1;
3337 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3339 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3340 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3344 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3346 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3347 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3349 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3352 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3354 const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3355 int i;
3357 load_ot_tables(hdc, psc);
3359 if (!psc->GPOS_Table || !psc->otm)
3360 return;
3362 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3364 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3366 LoadedFeature *feature;
3368 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3369 if (!feature)
3370 continue;
3372 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3377 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3379 LoadedFeature *feature;
3380 int i;
3382 if (!ShapingData[psa->eScript].requiredFeatures)
3383 return S_OK;
3385 load_ot_tables(hdc, psc);
3387 /* we need to have at least one of the required features */
3388 i = 0;
3389 while (ShapingData[psa->eScript].requiredFeatures[i])
3391 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3392 if (feature)
3393 return S_OK;
3394 i++;
3397 return USP_E_SCRIPT_NOT_IN_FONT;
3400 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3401 SCRIPT_ANALYSIS *psa, int cMaxTags,
3402 OPENTYPE_TAG *pScriptTags, int *pcTags)
3404 HRESULT hr;
3405 OPENTYPE_TAG searching = 0x00000000;
3407 load_ot_tables(hdc, psc);
3409 if (psa && scriptInformation[psa->eScript].scriptTag)
3410 searching = scriptInformation[psa->eScript].scriptTag;
3412 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3413 if (FAILED(hr))
3414 *pcTags = 0;
3415 return hr;
3418 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3419 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3420 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3421 int *pcTags)
3423 HRESULT hr;
3424 OPENTYPE_TAG searching = 0x00000000;
3425 BOOL fellback = FALSE;
3427 load_ot_tables(hdc, psc);
3429 if (psa && psc->userLang != 0)
3430 searching = psc->userLang;
3432 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3433 if (FAILED(hr))
3435 fellback = TRUE;
3436 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3439 if (FAILED(hr) || fellback)
3440 *pcTags = 0;
3441 if (SUCCEEDED(hr) && fellback && psa)
3442 hr = E_INVALIDARG;
3443 return hr;
3446 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3447 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3448 OPENTYPE_TAG tagLangSys, int cMaxTags,
3449 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3451 HRESULT hr;
3452 BOOL filter = FALSE;
3454 load_ot_tables(hdc, psc);
3456 if (psa && scriptInformation[psa->eScript].scriptTag)
3458 FIXME("Filtering not implemented\n");
3459 filter = TRUE;
3462 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3464 if (FAILED(hr))
3465 *pcTags = 0;
3466 return hr;