comdlg32: Specify a context for the luminance and saturation abbreviations.
[wine/multimedia.git] / dlls / usp10 / shape.c
blob5f71d6cff199ff8ffdcdf07ff5e344aa475fb1be
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #define FIRST_ARABIC_CHAR 0x0600
39 #define LAST_ARABIC_CHAR 0x06ff
41 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
42 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
62 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
63 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 );
64 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 );
65 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 );
66 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 );
67 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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
79 extern const unsigned short indic_syllabic_table[];
80 extern const unsigned short wine_shaping_table[];
81 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
83 enum joining_types {
84 jtU,
85 jtT,
86 jtR,
87 jtL,
88 jtD,
89 jtC
92 enum joined_forms {
93 Xn=0,
94 Xr,
95 Xl,
96 Xm,
97 /* Syriac Alaph */
98 Afj,
99 Afn,
103 typedef struct tagVowelComponents
105 WCHAR base;
106 WCHAR parts[3];
107 } VowelComponents;
109 typedef struct tagConsonantComponents
111 WCHAR parts[3];
112 WCHAR output;
113 } ConsonantComponents;
115 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
117 /* the orders of joined_forms and contextual_features need to line up */
118 static const char* contextual_features[] =
120 "isol",
121 "fina",
122 "init",
123 "medi",
124 /* Syriac Alaph */
125 "med2",
126 "fin2",
127 "fin3"
130 static OPENTYPE_FEATURE_RECORD standard_features[] =
132 { MS_MAKE_TAG('c','c','m','p'), 1},
133 { MS_MAKE_TAG('l','o','c','l'), 1},
136 static OPENTYPE_FEATURE_RECORD latin_features[] =
138 { MS_MAKE_TAG('l','i','g','a'), 1},
139 { MS_MAKE_TAG('c','l','i','g'), 1},
142 static OPENTYPE_FEATURE_RECORD arabic_features[] =
144 { MS_MAKE_TAG('r','l','i','g'), 1},
145 { MS_MAKE_TAG('c','a','l','t'), 1},
146 { MS_MAKE_TAG('l','i','g','a'), 1},
147 { MS_MAKE_TAG('d','l','i','g'), 1},
148 { MS_MAKE_TAG('c','s','w','h'), 1},
149 { MS_MAKE_TAG('m','s','e','t'), 1},
152 static const char* required_arabic_features[] =
154 "fina",
155 "init",
156 "medi",
157 "rlig",
158 NULL
161 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
163 { MS_MAKE_TAG('d','l','i','g'), 0},
166 static OPENTYPE_FEATURE_RECORD syriac_features[] =
168 { MS_MAKE_TAG('r','l','i','g'), 1},
169 { MS_MAKE_TAG('c','a','l','t'), 1},
170 { MS_MAKE_TAG('l','i','g','a'), 1},
171 { MS_MAKE_TAG('d','l','i','g'), 1},
174 static const char* required_syriac_features[] =
176 "fina",
177 "fin2",
178 "fin3",
179 "init",
180 "medi",
181 "med2",
182 "rlig",
183 NULL
186 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
188 /* Presentation forms */
189 { MS_MAKE_TAG('b','l','w','s'), 1},
190 { MS_MAKE_TAG('a','b','v','s'), 1},
191 { MS_MAKE_TAG('p','s','t','s'), 1},
194 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
196 { MS_MAKE_TAG('a','b','v','s'), 1},
197 { MS_MAKE_TAG('b','l','w','s'), 1},
200 static OPENTYPE_FEATURE_RECORD phags_features[] =
202 { MS_MAKE_TAG('a','b','v','s'), 1},
203 { MS_MAKE_TAG('b','l','w','s'), 1},
204 { MS_MAKE_TAG('c','a','l','t'), 1},
207 static OPENTYPE_FEATURE_RECORD thai_features[] =
209 { MS_MAKE_TAG('c','c','m','p'), 1},
212 static const char* required_lao_features[] =
214 "ccmp",
215 NULL
218 static const char* required_devanagari_features[] =
220 "nukt",
221 "akhn",
222 "rphf",
223 "blwf",
224 "half",
225 "vatu",
226 "pres",
227 "abvs",
228 "blws",
229 "psts",
230 "haln",
231 NULL
234 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
236 { MS_MAKE_TAG('p','r','e','s'), 1},
237 { MS_MAKE_TAG('a','b','v','s'), 1},
238 { MS_MAKE_TAG('b','l','w','s'), 1},
239 { MS_MAKE_TAG('p','s','t','s'), 1},
240 { MS_MAKE_TAG('h','a','l','n'), 1},
241 { MS_MAKE_TAG('c','a','l','t'), 1},
244 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
246 { MS_MAKE_TAG('l','i','g','a'), 1},
247 { MS_MAKE_TAG('c','l','i','g'), 1},
250 static const char* required_bengali_features[] =
252 "nukt",
253 "akhn",
254 "rphf",
255 "blwf",
256 "half",
257 "vatu",
258 "pstf",
259 "init",
260 "abvs",
261 "blws",
262 "psts",
263 "haln",
264 NULL
267 static const char* required_gurmukhi_features[] =
269 "nukt",
270 "akhn",
271 "rphf",
272 "blwf",
273 "half",
274 "pstf",
275 "vatu",
276 "cjct",
277 "pres",
278 "abvs",
279 "blws",
280 "psts",
281 "haln",
282 "calt",
283 NULL
286 static const char* required_oriya_features[] =
288 "nukt",
289 "akhn",
290 "rphf",
291 "blwf",
292 "pstf",
293 "cjct",
294 "pres",
295 "abvs",
296 "blws",
297 "psts",
298 "haln",
299 "calt",
300 NULL
303 static const char* required_tamil_features[] =
305 "nukt",
306 "akhn",
307 "rphf",
308 "pref",
309 "half",
310 "pres",
311 "abvs",
312 "blws",
313 "psts",
314 "haln",
315 "calt",
316 NULL
319 static const char* required_telugu_features[] =
321 "nukt",
322 "akhn",
323 "rphf",
324 "pref",
325 "half",
326 "pstf",
327 "cjct",
328 "pres",
329 "abvs",
330 "blws",
331 "psts",
332 "haln",
333 "calt",
334 NULL
337 static OPENTYPE_FEATURE_RECORD khmer_features[] =
339 { MS_MAKE_TAG('p','r','e','s'), 1},
340 { MS_MAKE_TAG('b','l','w','s'), 1},
341 { MS_MAKE_TAG('a','b','v','s'), 1},
342 { MS_MAKE_TAG('p','s','t','s'), 1},
343 { MS_MAKE_TAG('c','l','i','g'), 1},
346 static const char* required_khmer_features[] =
348 "pref",
349 "blwf",
350 "abvf",
351 "pstf",
352 "pres",
353 "blws",
354 "abvs",
355 "psts",
356 "clig",
357 NULL
360 static OPENTYPE_FEATURE_RECORD no_features[] =
361 { };
363 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
365 { MS_MAKE_TAG('c','c','m','p'), 1},
366 { MS_MAKE_TAG('l','o','c','l'), 1},
367 { MS_MAKE_TAG('c','a','l','t'), 1},
368 { MS_MAKE_TAG('l','i','g','a'), 1},
371 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
373 { MS_MAKE_TAG('c','c','m','p'), 1},
374 { MS_MAKE_TAG('l','o','c','l'), 1},
375 { MS_MAKE_TAG('c','a','l','t'), 1},
376 { MS_MAKE_TAG('r','l','i','g'), 1},
379 typedef struct ScriptShapeDataTag {
380 TEXTRANGE_PROPERTIES defaultTextRange;
381 const char** requiredFeatures;
382 OPENTYPE_TAG newOtTag;
383 ContextualShapingProc contextProc;
384 ShapeCharGlyphPropProc charGlyphPropProc;
385 } ScriptShapeData;
387 /* in order of scripts */
388 static const ScriptShapeData ShapingData[] =
390 {{ standard_features, 2}, NULL, 0, NULL, NULL},
391 {{ latin_features, 2}, NULL, 0, NULL, NULL},
392 {{ latin_features, 2}, NULL, 0, NULL, NULL},
393 {{ latin_features, 2}, NULL, 0, NULL, NULL},
394 {{ standard_features, 2}, NULL, 0, NULL, NULL},
395 {{ latin_features, 2}, NULL, 0, NULL, NULL},
396 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
397 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
398 {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
399 {{ syriac_features, 4}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
400 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
401 {{ NULL, 0}, NULL, 0, NULL, ShapeCharGlyphProp_None},
402 {{ standard_features, 2}, NULL, 0, NULL, NULL},
403 {{ standard_features, 2}, NULL, 0, NULL, NULL},
404 {{ standard_features, 2}, NULL, 0, NULL, NULL},
405 {{ standard_features, 2}, NULL, 0, NULL, NULL},
406 {{ sinhala_features, 3}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
407 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
408 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
409 {{ phags_features, 3}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
410 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
411 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
412 {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
413 {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
414 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
415 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
416 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
417 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
418 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
419 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
420 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
421 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
422 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
423 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
424 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
425 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
426 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
427 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
428 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
429 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
430 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
431 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
432 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
433 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
434 {{ standard_features, 2}, NULL, 0, NULL, NULL},
435 {{ latin_features, 2}, NULL, 0, NULL, NULL},
436 {{ standard_features, 2}, NULL, 0, NULL, NULL},
437 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
438 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
439 {{ standard_features, 2}, NULL, 0, NULL, NULL},
440 {{ standard_features, 2}, NULL, 0, NULL, NULL},
441 {{ standard_features, 2}, NULL, 0, NULL, NULL},
442 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
443 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
444 {{ no_features, 0}, NULL, 0, NULL, NULL},
445 {{ no_features, 0}, NULL, 0, NULL, NULL},
446 {{ no_features, 0}, NULL, 0, NULL, NULL},
447 {{ no_features, 0}, NULL, 0, NULL, NULL},
448 {{ no_features, 0}, NULL, 0, NULL, NULL},
449 {{ no_features, 0}, NULL, 0, NULL, NULL},
450 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
451 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
452 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
453 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
454 {{ no_features, 0}, NULL, 0, NULL, NULL},
455 {{ no_features, 0}, NULL, 0, NULL, NULL},
456 {{ no_features, 0}, NULL, 0, NULL, NULL},
457 {{ no_features, 0}, NULL, 0, NULL, NULL},
458 {{ no_features, 0}, NULL, 0, NULL, NULL},
459 {{ no_features, 0}, NULL, 0, NULL, NULL},
460 {{ no_features, 0}, NULL, 0, NULL, NULL},
461 {{ no_features, 0}, NULL, 0, NULL, NULL},
462 {{ no_features, 0}, NULL, 0, NULL, NULL},
463 {{ no_features, 0}, NULL, 0, NULL, NULL},
464 {{ no_features, 0}, NULL, 0, NULL, NULL},
465 {{ no_features, 0}, NULL, 0, NULL, NULL},
466 {{ no_features, 0}, NULL, 0, NULL, NULL},
467 {{ no_features, 0}, NULL, 0, NULL, NULL},
468 {{ no_features, 0}, NULL, 0, NULL, NULL},
469 {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
470 {{ latin_features, 2}, NULL, 0, NULL, NULL},
471 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
474 extern scriptData scriptInformation[];
476 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
478 int i;
479 int out_index = GSUB_E_NOGLYPH;
481 TRACE("%i lookups\n", feature->lookup_count);
482 for (i = 0; i < feature->lookup_count; i++)
484 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
485 if (out_index != GSUB_E_NOGLYPH)
486 break;
488 if (out_index == GSUB_E_NOGLYPH)
489 TRACE("lookups found no glyphs\n");
490 else
492 int out2;
493 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
494 if (out2!=GSUB_E_NOGLYPH)
495 out_index = out2;
497 return out_index;
500 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
502 UINT charset;
504 if (psc->userScript != 0)
506 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
507 return ShapingData[psa->eScript].newOtTag;
508 else
509 return psc->userScript;
512 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
513 return ShapingData[psa->eScript].newOtTag;
515 if (scriptInformation[psa->eScript].scriptTag)
516 return scriptInformation[psa->eScript].scriptTag;
519 * fall back to the font charset
521 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
522 switch (charset)
524 case ANSI_CHARSET:
525 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
526 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
527 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
528 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
529 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
530 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
531 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
532 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
533 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
534 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
535 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
536 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
537 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
538 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
539 default: return MS_MAKE_TAG('l','a','t','n');
543 static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
545 LoadedFeature *feature = NULL;
547 if (psc->GSUB_Table)
549 int attempt = 2;
550 OPENTYPE_TAG tags;
551 OPENTYPE_TAG language;
552 OPENTYPE_TAG script;
553 int cTags;
557 script = get_opentype_script(hdc,psa,psc,(attempt==2));
558 if (psc->userLang != 0)
559 language = psc->userLang;
560 else
561 language = MS_MAKE_TAG('d','f','l','t');
562 attempt--;
564 OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
566 } while(attempt && !feature);
568 /* try in the default (latin) table */
569 if (!feature)
570 OpenType_GSUB_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
573 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
574 return feature;
577 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)
579 LoadedFeature *feature;
581 feature = load_GSUB_feature(hdc, psa, psc, feat);
582 if (!feature)
583 return GSUB_E_NOFEATURE;
585 TRACE("applying feature %s\n",feat);
586 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
589 static VOID *load_gsub_table(HDC hdc)
591 VOID* GSUB_Table = NULL;
592 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
593 if (length != GDI_ERROR)
595 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
596 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
597 TRACE("Loaded GSUB table of %i bytes\n",length);
599 return GSUB_Table;
602 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)
604 WORD *glyphs;
605 INT glyph_count = count;
606 INT rc;
608 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
609 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
610 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
611 if (rc > GSUB_E_NOGLYPH)
612 rc = count - glyph_count;
613 else
614 rc = 0;
616 HeapFree(GetProcessHeap(),0,glyphs);
617 return rc;
620 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
622 int i;
624 for (i = 0; i < cGlyphs; i++)
626 if (!pGlyphProp[i].sva.fClusterStart)
628 int j;
629 for (j = 0; j < cChars; j++)
631 if (pwLogClust[j] == i)
633 int k = j;
634 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
635 k-=1;
636 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
637 pwLogClust[j] = pwLogClust[k];
644 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
646 if (changeCount == 0)
647 return;
648 else
650 int i;
651 int target_glyph = nextIndex - write_dir;
652 int seeking_glyph;
653 int target_index = -1;
654 int replacing_glyph = -1;
655 int changed = 0;
656 int top_logclust = 0;
658 if (changeCount > 0)
660 if (write_dir > 0)
661 target_glyph = nextIndex - changeCount;
662 else
663 target_glyph = nextIndex + (changeCount + 1);
666 seeking_glyph = target_glyph;
667 for (i = 0; i < chars; i++)
668 if (pwLogClust[i] > top_logclust)
669 top_logclust = pwLogClust[i];
671 do {
672 if (write_dir > 0)
673 for (i = 0; i < chars; i++)
675 if (pwLogClust[i] == seeking_glyph)
677 target_index = i;
678 break;
681 else
682 for (i = chars - 1; i >= 0; i--)
684 if (pwLogClust[i] == seeking_glyph)
686 target_index = i;
687 break;
690 if (target_index == -1)
691 seeking_glyph ++;
693 while (target_index == -1 && seeking_glyph <= top_logclust);
695 if (target_index == -1)
697 ERR("Unable to find target glyph\n");
698 return;
701 if (changeCount < 0)
703 /* merge glyphs */
704 for(i = target_index; i < chars && i >= 0; i+=write_dir)
706 if (pwLogClust[i] == target_glyph)
707 continue;
708 if(pwLogClust[i] == replacing_glyph)
709 pwLogClust[i] = target_glyph;
710 else
712 changed--;
713 if (changed >= changeCount)
715 replacing_glyph = pwLogClust[i];
716 pwLogClust[i] = target_glyph;
718 else
719 break;
723 /* renumber trailing indexes*/
724 for(i = target_index; i < chars && i >= 0; i+=write_dir)
726 if (pwLogClust[i] != target_glyph)
727 pwLogClust[i] += changeCount;
730 else
732 for(i = target_index; i < chars && i >= 0; i+=write_dir)
733 pwLogClust[i] += changeCount;
738 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 )
740 if (psc->GSUB_Table)
742 LoadedFeature *feature;
743 int lookup_index;
745 feature = load_GSUB_feature(hdc, psa, psc, feat);
746 if (!feature)
747 return GSUB_E_NOFEATURE;
749 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
750 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
752 int i;
754 if (write_dir > 0)
755 i = 0;
756 else
757 i = *pcGlyphs-1;
758 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
759 while(i < *pcGlyphs && i >= 0)
761 INT nextIndex;
762 INT prevCount = *pcGlyphs;
764 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
765 if (*pcGlyphs != prevCount)
767 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
768 i = nextIndex;
770 else
771 i+=write_dir;
774 return *pcGlyphs;
776 return GSUB_E_NOFEATURE;
779 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
781 OPENTYPE_TAG tag;
782 HRESULT hr;
783 int count = 0;
785 hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL);
787 return(SUCCEEDED(hr));
790 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
792 if (i + delta < 0)
793 return 0;
794 if ( i+ delta >= cchLen)
795 return 0;
797 i += delta;
799 return chars[i];
802 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
804 if (i + delta < 0)
806 if (psa->fLinkBefore)
807 return jtR;
808 else
809 return jtU;
811 if ( i+ delta >= cchLen)
813 if (psa->fLinkAfter)
814 return jtL;
815 else
816 return jtU;
819 i += delta;
821 if (context_type[i] == jtT)
822 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
823 else
824 return context_type[i];
827 static inline BOOL right_join_causing(CHAR joining_type)
829 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
832 static inline BOOL left_join_causing(CHAR joining_type)
834 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
837 static inline BOOL word_break_causing(WCHAR chr)
839 /* we are working within a string of characters already guareented to
840 be within one script, Syriac, so we do not worry about any character
841 other than the space character outside of that range */
842 return (chr == 0 || chr == 0x20 );
846 * ContextualShape_Arabic
848 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
850 CHAR *context_type;
851 INT *context_shape;
852 INT dirR, dirL;
853 int i;
855 if (*pcGlyphs != cChars)
857 ERR("Number of Glyphs and Chars need to match at the beginning\n");
858 return;
861 if (!psa->fLogicalOrder && psa->fRTL)
863 dirR = 1;
864 dirL = -1;
866 else
868 dirR = -1;
869 dirL = 1;
872 if (!psc->GSUB_Table)
873 psc->GSUB_Table = load_gsub_table(hdc);
875 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
876 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
878 for (i = 0; i < cChars; i++)
879 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
881 for (i = 0; i < cChars; i++)
883 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
884 context_shape[i] = Xr;
885 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
886 context_shape[i] = Xl;
887 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)))
888 context_shape[i] = Xm;
889 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
890 context_shape[i] = Xr;
891 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
892 context_shape[i] = Xl;
893 else
894 context_shape[i] = Xn;
897 /* Contextual Shaping */
898 i = 0;
899 while(i < *pcGlyphs)
901 BOOL shaped = FALSE;
903 if (psc->GSUB_Table)
905 INT nextIndex;
906 INT prevCount = *pcGlyphs;
907 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
908 if (nextIndex > GSUB_E_NOGLYPH)
910 i = nextIndex;
911 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
913 shaped = (nextIndex > GSUB_E_NOGLYPH);
916 if (!shaped)
918 if (context_shape[i] == Xn)
920 WORD newGlyph = pwOutGlyphs[i];
921 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
923 /* fall back to presentation form B */
924 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
925 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
926 pwOutGlyphs[i] = newGlyph;
929 i++;
933 HeapFree(GetProcessHeap(),0,context_shape);
934 HeapFree(GetProcessHeap(),0,context_type);
938 * ContextualShape_Syriac
941 #define ALAPH 0x710
942 #define DALATH 0x715
943 #define RISH 0x72A
945 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
947 CHAR *context_type;
948 INT *context_shape;
949 INT dirR, dirL;
950 int i;
952 if (*pcGlyphs != cChars)
954 ERR("Number of Glyphs and Chars need to match at the beginning\n");
955 return;
958 if (!psa->fLogicalOrder && psa->fRTL)
960 dirR = 1;
961 dirL = -1;
963 else
965 dirR = -1;
966 dirL = 1;
969 if (!psc->GSUB_Table)
970 psc->GSUB_Table = load_gsub_table(hdc);
972 if (!psc->GSUB_Table)
973 return;
975 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
976 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
978 for (i = 0; i < cChars; i++)
979 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
981 for (i = 0; i < cChars; i++)
983 if (pwcChars[i] == ALAPH)
985 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
987 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
988 context_shape[i] = Afj;
989 else if ( rchar != DALATH && rchar != RISH &&
990 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
991 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
992 context_shape[i] = Afn;
993 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
994 context_shape[i] = Afx;
995 else
996 context_shape[i] = Xn;
998 else if (context_type[i] == jtR &&
999 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1000 context_shape[i] = Xr;
1001 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1002 context_shape[i] = Xl;
1003 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)))
1004 context_shape[i] = Xm;
1005 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1006 context_shape[i] = Xr;
1007 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1008 context_shape[i] = Xl;
1009 else
1010 context_shape[i] = Xn;
1013 /* Contextual Shaping */
1014 i = 0;
1015 while(i < *pcGlyphs)
1017 INT nextIndex;
1018 INT prevCount = *pcGlyphs;
1019 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1020 if (nextIndex > GSUB_E_NOGLYPH)
1022 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1023 i = nextIndex;
1025 else
1026 i++;
1029 HeapFree(GetProcessHeap(),0,context_shape);
1030 HeapFree(GetProcessHeap(),0,context_type);
1034 * ContextualShape_Phags_pa
1037 #define phags_pa_CANDRABINDU 0xA873
1038 #define phags_pa_START 0xA840
1039 #define phags_pa_END 0xA87F
1041 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1043 INT *context_shape;
1044 INT dirR, dirL;
1045 int i;
1047 if (*pcGlyphs != cChars)
1049 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1050 return;
1053 if (!psa->fLogicalOrder && psa->fRTL)
1055 dirR = 1;
1056 dirL = -1;
1058 else
1060 dirR = -1;
1061 dirL = 1;
1064 if (!psc->GSUB_Table)
1065 psc->GSUB_Table = load_gsub_table(hdc);
1067 if (!psc->GSUB_Table)
1068 return;
1070 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1072 for (i = 0; i < cChars; i++)
1074 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1076 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1077 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1078 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1079 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1081 if (jrchar && jlchar)
1082 context_shape[i] = Xm;
1083 else if (jrchar)
1084 context_shape[i] = Xr;
1085 else if (jlchar)
1086 context_shape[i] = Xl;
1087 else
1088 context_shape[i] = Xn;
1090 else
1091 context_shape[i] = -1;
1094 /* Contextual Shaping */
1095 i = 0;
1096 while(i < *pcGlyphs)
1098 if (context_shape[i] >= 0)
1100 INT nextIndex;
1101 INT prevCount = *pcGlyphs;
1102 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1103 if (nextIndex > GSUB_E_NOGLYPH)
1105 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1106 i = nextIndex;
1108 else
1109 i++;
1111 else
1112 i++;
1115 HeapFree(GetProcessHeap(),0,context_shape);
1118 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1120 int i;
1122 /* Replace */
1123 pwOutChars[cWalk] = replacements[0];
1124 cWalk=cWalk+1;
1126 /* Insert */
1127 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1129 int j;
1130 for (j = *pcChars; j > cWalk; j--)
1131 pwOutChars[j] = pwOutChars[j-1];
1132 *pcChars= *pcChars+1;
1133 pwOutChars[cWalk] = replacements[i];
1134 cWalk = cWalk+1;
1138 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1140 int i;
1141 int cWalk;
1143 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1145 for (i = 0; vowels[i].base != 0x0; i++)
1147 if (pwOutChars[cWalk] == vowels[i].base)
1149 int o = 0;
1150 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1151 if (vowels[i].parts[1]) { cWalk++; o++; }
1152 if (vowels[i].parts[2]) { cWalk++; o++; }
1153 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1154 break;
1160 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1162 int i;
1163 int offset = 0;
1164 int cWalk;
1166 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1168 for (i = 0; consonants[i].output!= 0x0; i++)
1170 int j;
1171 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1172 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1173 break;
1175 if (consonants[i].parts[j]==0x0) /* matched all */
1177 int k;
1178 j--;
1179 pwOutChars[cWalk] = consonants[i].output;
1180 for(k = cWalk+1; k < *pcChars - j; k++)
1181 pwOutChars[k] = pwOutChars[k+j];
1182 *pcChars = *pcChars - j;
1183 for (k = j ; k > 0; k--)
1184 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1185 offset += j;
1186 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1187 pwLogClust[k]--;
1188 break;
1191 cWalk++;
1195 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1197 if (s->ralf >= 0)
1199 int j;
1200 WORD Ra = pwChar[s->start];
1201 WORD H = pwChar[s->start+1];
1203 TRACE("Doing reorder of Ra to %i\n",s->base);
1204 for (j = s->start; j < s->base-1; j++)
1205 pwChar[j] = pwChar[j+2];
1206 pwChar[s->base-1] = Ra;
1207 pwChar[s->base] = H;
1209 s->ralf = s->base-1;
1210 s->base -= 2;
1214 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1216 if (s->ralf >= 0)
1218 int j,loc;
1219 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1220 WORD Ra = pwChar[s->start];
1221 WORD H = pwChar[s->start+1];
1222 for (loc = s->end; loc > stop; loc--)
1223 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1224 break;
1226 TRACE("Doing reorder of Ra to %i\n",loc);
1227 for (j = s->start; j < loc-1; j++)
1228 pwChar[j] = pwChar[j+2];
1229 pwChar[loc-1] = Ra;
1230 pwChar[loc] = H;
1232 s->ralf = loc-1;
1233 s->base -= 2;
1234 if (s->blwf >= 0) s->blwf -= 2;
1235 if (s->pref >= 0) s->pref -= 2;
1239 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1241 if (s->ralf >= 0)
1243 int j;
1244 WORD Ra = pwChar[s->start];
1245 WORD H = pwChar[s->start+1];
1247 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1248 for (j = s->start; j < s->end-1; j++)
1249 pwChar[j] = pwChar[j+2];
1250 pwChar[s->end-1] = Ra;
1251 pwChar[s->end] = H;
1253 s->ralf = s->end-1;
1254 s->base -= 2;
1255 if (s->blwf >= 0) s->blwf -= 2;
1256 if (s->pref >= 0) s->pref -= 2;
1260 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1262 int i;
1264 /* reorder Matras */
1265 if (s->end > s->base)
1267 for (i = 1; i <= s->end-s->base; i++)
1269 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1271 int j;
1272 WCHAR c = pwChar[s->base+i];
1273 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1274 for (j = s->base+i; j > s->base; j--)
1275 pwChar[j] = pwChar[j-1];
1276 pwChar[s->base] = c;
1278 if (s->ralf >= s->base) s->ralf++;
1279 if (s->blwf >= s->base) s->blwf++;
1280 if (s->pref >= s->base) s->pref++;
1281 s->base ++;
1287 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1289 int i;
1291 /* reorder Matras */
1292 if (s->end > s->base)
1294 for (i = 1; i <= s->end-s->base; i++)
1296 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1298 int j;
1299 WCHAR c = pwChar[s->base+i];
1300 TRACE("Doing reorder of %x to %i\n",c,s->start);
1301 for (j = s->base+i; j > s->start; j--)
1302 pwChar[j] = pwChar[j-1];
1303 pwChar[s->start] = c;
1305 if (s->ralf >= 0) s->ralf++;
1306 if (s->blwf >= 0) s->blwf++;
1307 if (s->pref >= 0) s->pref++;
1308 s->base ++;
1314 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1316 if (s->blwf >= 0 && g->blwf > g->base)
1318 int j,loc;
1319 int g_offset;
1320 for (loc = s->end; loc > s->blwf; loc--)
1321 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1322 break;
1324 g_offset = (loc - s->blwf) - 1;
1326 if (loc != s->blwf)
1328 WORD blwf = glyphs[g->blwf];
1329 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1330 /* do not care about the pwChar array anymore, just the glyphs */
1331 for (j = 0; j < g_offset; j++)
1332 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1333 glyphs[g->blwf + g_offset] = blwf;
1338 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1340 int i;
1342 /* reorder previously moved Matras to correct position*/
1343 for (i = s->start; i < s->base; i++)
1345 if (lexical(pwChar[i]) == lex_Matra_pre)
1347 int j;
1348 int g_start = g->start + i - s->start;
1349 if (g_start < g->base -1 )
1351 WCHAR og = glyphs[g_start];
1352 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1353 for (j = g_start; j < g->base-1; j++)
1354 glyphs[j] = glyphs[j+1];
1355 glyphs[g->base-1] = og;
1361 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1363 if (s->pref >= 0 && g->pref > g->base)
1365 int j;
1366 WCHAR og = glyphs[g->pref];
1367 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1368 for (j = g->pref; j > g->base; j--)
1369 glyphs[j] = glyphs[j-1];
1370 glyphs[g->base] = og;
1374 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1376 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1377 if (s->start == s->base && s->base == s->end) return;
1378 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1380 Reorder_Ra_follows_base(pwChar, s, lexical);
1381 Reorder_Matra_precede_base(pwChar, s, lexical);
1384 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1386 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1387 if (s->start == s->base && s->base == s->end) return;
1388 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1390 Reorder_Ra_follows_matra(pwChar, s, lexical);
1391 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1394 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1396 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1397 if (s->start == s->base && s->base == s->end) return;
1398 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1400 Reorder_Ra_follows_base(pwChar, s, lexical);
1401 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1404 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1406 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1407 if (s->start == s->base && s->base == s->end) return;
1408 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1410 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1411 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1414 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1416 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1417 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1418 if (s->start == s->base && s->base == s->end) return;
1419 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1421 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1424 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1426 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1427 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1428 if (s->start == s->base && s->base == s->end) return;
1429 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1431 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1432 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1436 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1438 if (shift == 0)
1439 return;
1441 if (glyph_index->start > index)
1442 glyph_index->start += shift;
1443 if (glyph_index->base > index)
1444 glyph_index->base+= shift;
1445 if (glyph_index->end > index)
1446 glyph_index->end+= shift;
1447 if (glyph_index->ralf > index)
1448 glyph_index->ralf+= shift;
1449 if (glyph_index->blwf > index)
1450 glyph_index->blwf+= shift;
1451 if (glyph_index->pref > index)
1452 glyph_index->pref+= shift;
1455 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 )
1457 int index = glyph_index->start;
1459 if (!feature)
1460 return;
1462 while(index <= glyph_index->end)
1464 INT nextIndex;
1465 INT prevCount = *pcGlyphs;
1466 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1467 if (nextIndex > GSUB_E_NOGLYPH)
1469 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1470 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1471 index = nextIndex;
1473 else
1474 index++;
1478 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1480 int i = 0;
1481 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)))))
1482 i++;
1483 if (index + i <= end-1)
1484 return index + i;
1485 else
1486 return -1;
1489 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)
1491 INT index, nextIndex;
1492 INT count,g_offset;
1494 count = syllable->base - syllable->start;
1496 g_offset = 0;
1497 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1498 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1500 INT prevCount = *pcGlyphs;
1501 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1502 if (nextIndex > GSUB_E_NOGLYPH)
1504 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1505 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1506 g_offset += (*pcGlyphs - prevCount);
1509 index+=2;
1510 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1514 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)
1516 INT nextIndex;
1517 INT prevCount = *pcGlyphs;
1519 if (syllable->ralf >= 0)
1521 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1522 if (nextIndex > GSUB_E_NOGLYPH)
1524 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1525 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1530 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1532 int i = 0;
1533 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1534 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1535 is_consonant(lexical(pwChars[index+i+1])))))
1536 i++;
1537 if (index + i <= end-1)
1538 return index+i;
1539 else
1540 return -1;
1543 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)
1545 INT index, nextIndex;
1546 INT count, g_offset=0;
1547 INT ralf = syllable->ralf;
1549 count = syllable->end - syllable->base;
1551 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
1553 while (index >= 0)
1555 INT prevCount = *pcGlyphs;
1556 if (ralf >=0 && ralf < index)
1558 g_offset--;
1559 ralf = -1;
1562 if (!modern)
1564 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1565 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1566 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1569 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
1570 if (nextIndex > GSUB_E_NOGLYPH)
1572 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1573 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
1574 g_offset += (*pcGlyphs - prevCount);
1576 else if (!modern)
1578 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1579 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1580 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1583 index+=2;
1584 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
1588 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)
1590 int c;
1591 int overall_shift = 0;
1592 LoadedFeature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
1593 LoadedFeature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
1594 LoadedFeature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
1595 LoadedFeature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
1596 LoadedFeature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
1597 LoadedFeature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
1598 LoadedFeature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
1599 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
1600 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
1601 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
1602 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
1603 IndicSyllable glyph_indexs;
1605 for (c = 0; c < syllable_count; c++)
1607 int old_end;
1608 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
1609 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
1610 old_end = glyph_indexs.end;
1612 if (locl)
1614 TRACE("applying feature locl\n");
1615 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
1617 if (nukt)
1619 TRACE("applying feature nukt\n");
1620 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
1622 if (akhn)
1624 TRACE("applying feature akhn\n");
1625 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
1628 if (rphf)
1629 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
1630 if (rkrf)
1632 TRACE("applying feature rkrf\n");
1633 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
1635 if (pref)
1636 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
1637 if (blwf)
1639 if (!modern)
1640 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
1642 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
1645 if (half)
1646 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
1647 if (pstf)
1649 TRACE("applying feature pstf\n");
1650 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
1652 if (vatu)
1654 TRACE("applying feature vatu\n");
1655 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
1657 if (cjct)
1659 TRACE("applying feature cjct\n");
1660 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
1663 if (second_reorder)
1664 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
1666 overall_shift += glyph_indexs.end - old_end;
1670 static inline int unicode_lex(WCHAR c)
1672 int type;
1674 if (!c) return lex_Generic;
1675 if (c == 0x200D) return lex_ZWJ;
1676 if (c == 0x200C) return lex_ZWNJ;
1677 if (c == 0x00A0) return lex_NBSP;
1679 type = get_table_entry( indic_syllabic_table, c );
1681 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
1683 switch( type )
1685 case 0x0d07: /* Unknown */
1686 case 0x0e07: /* Unknwon */
1687 default: return lex_Generic;
1688 case 0x0001:
1689 case 0x0002:
1690 case 0x0011:
1691 case 0x0012:
1692 case 0x0013:
1693 case 0x0014: return lex_Modifier;
1694 case 0x0003:
1695 case 0x0009:
1696 case 0x000a:
1697 case 0x000b:
1698 case 0x000d:
1699 case 0x000e:
1700 case 0x000f:
1701 case 0x0010: return lex_Consonant;
1702 case 0x0004: return lex_Nukta;
1703 case 0x0005: return lex_Halant;
1704 case 0x0006:
1705 case 0x0008: return lex_Vowel;
1706 case 0x0007:
1707 case 0x0107: return lex_Matra_post;
1708 case 0x0207:
1709 case 0x0307: return lex_Matra_pre;
1710 case 0x0807:
1711 case 0x0907:
1712 case 0x0a07:
1713 case 0x0b07:
1714 case 0x0c07:
1715 case 0x0407: return lex_Composed_Vowel;
1716 case 0x0507: return lex_Matra_above;
1717 case 0x0607: return lex_Matra_below;
1718 case 0x000c: return lex_Ra;
1722 static int sinhala_lex(WCHAR c)
1724 switch (c)
1726 case 0x0DDA:
1727 case 0x0DDD:
1728 case 0x0DDC:
1729 case 0x0DDE: return lex_Matra_post;
1730 default:
1731 return unicode_lex(c);
1735 static const VowelComponents Sinhala_vowels[] = {
1736 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
1737 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
1738 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
1739 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
1740 {0x0000, {0x0000,0x0000,0x0}}};
1742 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1744 int cCount = cChars;
1745 int i;
1746 WCHAR *input;
1747 IndicSyllable *syllables = NULL;
1748 int syllable_count = 0;
1750 if (*pcGlyphs != cChars)
1752 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1753 return;
1756 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
1758 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1760 /* Step 1: Decompose multi part vowels */
1761 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
1763 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1765 /* Step 2: Reorder within Syllables */
1766 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
1767 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1769 /* Step 3: Strip dangling joiners */
1770 for (i = 0; i < cCount; i++)
1772 if ((input[i] == 0x200D || input[i] == 0x200C) &&
1773 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
1774 input[i] = 0x0020;
1777 /* Step 4: Base Form application to syllables */
1778 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1779 *pcGlyphs = cCount;
1780 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
1782 HeapFree(GetProcessHeap(),0,input);
1783 HeapFree(GetProcessHeap(),0,syllables);
1786 static int devanagari_lex(WCHAR c)
1788 switch (c)
1790 case 0x0930: return lex_Ra;
1791 default:
1792 return unicode_lex(c);
1796 static const ConsonantComponents Devanagari_consonants[] ={
1797 {{0x0928, 0x093C, 0x00000}, 0x0929},
1798 {{0x0930, 0x093C, 0x00000}, 0x0931},
1799 {{0x0933, 0x093C, 0x00000}, 0x0934},
1800 {{0x0915, 0x093C, 0x00000}, 0x0958},
1801 {{0x0916, 0x093C, 0x00000}, 0x0959},
1802 {{0x0917, 0x093C, 0x00000}, 0x095A},
1803 {{0x091C, 0x093C, 0x00000}, 0x095B},
1804 {{0x0921, 0x093C, 0x00000}, 0x095C},
1805 {{0x0922, 0x093C, 0x00000}, 0x095D},
1806 {{0x092B, 0x093C, 0x00000}, 0x095E},
1807 {{0x092F, 0x093C, 0x00000}, 0x095F}};
1809 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1811 int cCount = cChars;
1812 WCHAR *input;
1813 IndicSyllable *syllables = NULL;
1814 int syllable_count = 0;
1815 BOOL modern = get_GSUB_Indic2(psa, psc);
1817 if (*pcGlyphs != cChars)
1819 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1820 return;
1823 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1824 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1826 /* Step 1: Compose Consonant and Nukta */
1827 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
1828 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1830 /* Step 2: Reorder within Syllables */
1831 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
1832 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1833 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1834 *pcGlyphs = cCount;
1836 /* Step 3: Base Form application to syllables */
1837 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
1839 HeapFree(GetProcessHeap(),0,input);
1840 HeapFree(GetProcessHeap(),0,syllables);
1843 static int bengali_lex(WCHAR c)
1845 switch (c)
1847 case 0x09B0: return lex_Ra;
1848 default:
1849 return unicode_lex(c);
1853 static const VowelComponents Bengali_vowels[] = {
1854 {0x09CB, {0x09C7,0x09BE,0x0000}},
1855 {0x09CC, {0x09C7,0x09D7,0x0000}},
1856 {0x0000, {0x0000,0x0000,0x0000}}};
1858 static const ConsonantComponents Bengali_consonants[] = {
1859 {{0x09A4,0x09CD,0x200D}, 0x09CE},
1860 {{0x09A1,0x09BC,0x0000}, 0x09DC},
1861 {{0x09A2,0x09BC,0x0000}, 0x09DD},
1862 {{0x09AF,0x09BC,0x0000}, 0x09DF},
1863 {{0x0000,0x0000,0x0000}, 0x0000}};
1865 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1867 int cCount = cChars;
1868 WCHAR *input;
1869 IndicSyllable *syllables = NULL;
1870 int syllable_count = 0;
1871 BOOL modern = get_GSUB_Indic2(psa, psc);
1873 if (*pcGlyphs != cChars)
1875 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1876 return;
1879 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
1880 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1882 /* Step 1: Decompose Vowels and Compose Consonents */
1883 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
1884 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
1885 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1887 /* Step 2: Reorder within Syllables */
1888 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
1889 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1890 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1891 *pcGlyphs = cCount;
1893 /* Step 3: Initial form is only applied to the beginning of words */
1894 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
1896 if (cCount == 0 || input[cCount] == 0x0020) /* space */
1898 int index = cCount;
1899 int gCount = 1;
1900 if (index > 0) index++;
1902 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
1906 /* Step 4: Base Form application to syllables */
1907 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
1909 HeapFree(GetProcessHeap(),0,input);
1910 HeapFree(GetProcessHeap(),0,syllables);
1913 static int gurmukhi_lex(WCHAR c)
1915 if (c == 0x0A71)
1916 return lex_Modifier;
1917 else
1918 return unicode_lex(c);
1921 static const ConsonantComponents Gurmukhi_consonants[] = {
1922 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
1923 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
1924 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
1925 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
1926 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
1927 {{0x0000,0x0000,0x0000}, 0x0000}};
1929 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1931 int cCount = cChars;
1932 WCHAR *input;
1933 IndicSyllable *syllables = NULL;
1934 int syllable_count = 0;
1935 BOOL modern = get_GSUB_Indic2(psa, psc);
1937 if (*pcGlyphs != cChars)
1939 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1940 return;
1943 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1944 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1946 /* Step 1: Compose Consonents */
1947 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
1948 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1950 /* Step 2: Reorder within Syllables */
1951 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
1952 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1953 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1954 *pcGlyphs = cCount;
1956 /* Step 3: Base Form application to syllables */
1957 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
1959 HeapFree(GetProcessHeap(),0,input);
1960 HeapFree(GetProcessHeap(),0,syllables);
1963 static int gujarati_lex(WCHAR c)
1965 switch (c)
1967 case 0x0AB0: return lex_Ra;
1968 default:
1969 return unicode_lex(c);
1973 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1975 int cCount = cChars;
1976 WCHAR *input;
1977 IndicSyllable *syllables = NULL;
1978 int syllable_count = 0;
1979 BOOL modern = get_GSUB_Indic2(psa, psc);
1981 if (*pcGlyphs != cChars)
1983 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1984 return;
1987 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1988 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1990 /* Step 1: Reorder within Syllables */
1991 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
1992 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1993 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1994 *pcGlyphs = cCount;
1996 /* Step 2: Base Form application to syllables */
1997 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
1999 HeapFree(GetProcessHeap(),0,input);
2000 HeapFree(GetProcessHeap(),0,syllables);
2003 static int oriya_lex(WCHAR c)
2005 switch (c)
2007 case 0x0B30: return lex_Ra;
2008 default:
2009 return unicode_lex(c);
2013 static const VowelComponents Oriya_vowels[] = {
2014 {0x0B48, {0x0B47,0x0B56,0x0000}},
2015 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2016 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2017 {0x0000, {0x0000,0x0000,0x0000}}};
2019 static const ConsonantComponents Oriya_consonants[] = {
2020 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2021 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2022 {{0x0000,0x0000,0x0000}, 0x0000}};
2024 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2026 int cCount = cChars;
2027 WCHAR *input;
2028 IndicSyllable *syllables = NULL;
2029 int syllable_count = 0;
2030 BOOL modern = get_GSUB_Indic2(psa, psc);
2032 if (*pcGlyphs != cChars)
2034 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2035 return;
2038 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2039 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2041 /* Step 1: Decompose Vowels and Compose Consonents */
2042 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2043 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2044 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2046 /* Step 2: Reorder within Syllables */
2047 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2048 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2049 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2050 *pcGlyphs = cCount;
2052 /* Step 3: Base Form application to syllables */
2053 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2055 HeapFree(GetProcessHeap(),0,input);
2056 HeapFree(GetProcessHeap(),0,syllables);
2059 static int tamil_lex(WCHAR c)
2061 return unicode_lex(c);
2064 static const VowelComponents Tamil_vowels[] = {
2065 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2066 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2067 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2068 {0x0000, {0x0000,0x0000,0x0000}}};
2070 static const ConsonantComponents Tamil_consonants[] = {
2071 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2072 {{0x0000,0x0000,0x0000}, 0x0000}};
2074 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2076 int cCount = cChars;
2077 WCHAR *input;
2078 IndicSyllable *syllables = NULL;
2079 int syllable_count = 0;
2080 BOOL modern = get_GSUB_Indic2(psa, psc);
2082 if (*pcGlyphs != cChars)
2084 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2085 return;
2088 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2089 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2091 /* Step 1: Decompose Vowels and Compose Consonents */
2092 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2093 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2094 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2096 /* Step 2: Reorder within Syllables */
2097 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2098 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2099 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2100 *pcGlyphs = cCount;
2102 /* Step 3: Base Form application to syllables */
2103 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2105 HeapFree(GetProcessHeap(),0,input);
2106 HeapFree(GetProcessHeap(),0,syllables);
2109 static int telugu_lex(WCHAR c)
2111 switch (c)
2113 case 0x0C43:
2114 case 0x0C44: return lex_Modifier;
2115 default:
2116 return unicode_lex(c);
2120 static const VowelComponents Telugu_vowels[] = {
2121 {0x0C48, {0x0C46,0x0C56,0x0000}},
2122 {0x0000, {0x0000,0x0000,0x0000}}};
2124 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2126 int cCount = cChars;
2127 WCHAR *input;
2128 IndicSyllable *syllables = NULL;
2129 int syllable_count = 0;
2130 BOOL modern = get_GSUB_Indic2(psa, psc);
2132 if (*pcGlyphs != cChars)
2134 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2135 return;
2138 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2139 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2141 /* Step 1: Decompose Vowels */
2142 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2143 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2145 /* Step 2: Reorder within Syllables */
2146 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2147 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2148 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2149 *pcGlyphs = cCount;
2151 /* Step 3: Base Form application to syllables */
2152 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2154 HeapFree(GetProcessHeap(),0,input);
2155 HeapFree(GetProcessHeap(),0,syllables);
2158 static int kannada_lex(WCHAR c)
2160 switch (c)
2162 case 0x0CB0: return lex_Ra;
2163 default:
2164 return unicode_lex(c);
2168 static const VowelComponents Kannada_vowels[] = {
2169 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2170 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2171 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2172 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2173 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2174 {0x0000, {0x0000,0x0000,0x0000}}};
2176 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2178 int cCount = cChars;
2179 WCHAR *input;
2180 IndicSyllable *syllables = NULL;
2181 int syllable_count = 0;
2182 BOOL modern = get_GSUB_Indic2(psa, psc);
2184 if (*pcGlyphs != cChars)
2186 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2187 return;
2190 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2191 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2193 /* Step 1: Decompose Vowels */
2194 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2195 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2197 /* Step 2: Reorder within Syllables */
2198 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2199 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2200 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2201 *pcGlyphs = cCount;
2203 /* Step 3: Base Form application to syllables */
2204 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2206 HeapFree(GetProcessHeap(),0,input);
2207 HeapFree(GetProcessHeap(),0,syllables);
2210 static int malayalam_lex(WCHAR c)
2212 return unicode_lex(c);
2215 static const VowelComponents Malayalam_vowels[] = {
2216 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2217 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2218 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2219 {0x0000, {0x0000,0x0000,0x0000}}};
2221 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2223 int cCount = cChars;
2224 WCHAR *input;
2225 IndicSyllable *syllables = NULL;
2226 int syllable_count = 0;
2227 BOOL modern = get_GSUB_Indic2(psa, psc);
2229 if (*pcGlyphs != cChars)
2231 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2232 return;
2235 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2236 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2238 /* Step 1: Decompose Vowels */
2239 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2240 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2242 /* Step 2: Reorder within Syllables */
2243 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2244 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2245 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2246 *pcGlyphs = cCount;
2248 /* Step 3: Base Form application to syllables */
2249 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2251 HeapFree(GetProcessHeap(),0,input);
2252 HeapFree(GetProcessHeap(),0,syllables);
2255 static int khmer_lex(WCHAR c)
2257 return unicode_lex(c);
2260 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2262 int cCount = cChars;
2263 WCHAR *input;
2264 IndicSyllable *syllables = NULL;
2265 int syllable_count = 0;
2267 if (*pcGlyphs != cChars)
2269 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2270 return;
2273 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2274 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2276 /* Step 1: Reorder within Syllables */
2277 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2278 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2279 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2280 *pcGlyphs = cCount;
2282 /* Step 2: Base Form application to syllables */
2283 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2285 HeapFree(GetProcessHeap(),0,input);
2286 HeapFree(GetProcessHeap(),0,syllables);
2289 static inline BOOL mongolian_wordbreak(WCHAR chr)
2291 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2294 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2296 INT *context_shape;
2297 INT dirL;
2298 int i;
2300 if (*pcGlyphs != cChars)
2302 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2303 return;
2306 if (!psa->fLogicalOrder && psa->fRTL)
2307 dirL = -1;
2308 else
2309 dirL = 1;
2311 if (!psc->GSUB_Table)
2312 psc->GSUB_Table = load_gsub_table(hdc);
2314 if (!psc->GSUB_Table)
2315 return;
2317 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2319 for (i = 0; i < cChars; i++)
2321 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2323 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2324 context_shape[i] = Xn;
2325 else
2326 context_shape[i] = Xl;
2328 else
2330 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2331 context_shape[i] = Xr;
2332 else
2333 context_shape[i] = Xm;
2337 /* Contextual Shaping */
2338 i = 0;
2339 while(i < *pcGlyphs)
2341 INT nextIndex;
2342 INT prevCount = *pcGlyphs;
2343 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2344 if (nextIndex > GSUB_E_NOGLYPH)
2346 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2347 i = nextIndex;
2349 else
2350 i++;
2353 HeapFree(GetProcessHeap(),0,context_shape);
2356 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
2358 int i,k;
2360 for (i = 0; i < cGlyphs; i++)
2362 int char_index[20];
2363 int char_count = 0;
2365 for (k = 0; k < cChars; k++)
2367 if (pwLogClust[k] == i)
2369 char_index[char_count] = k;
2370 char_count++;
2374 if (char_count == 0)
2375 continue;
2377 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2379 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2380 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2382 else
2383 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2386 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2387 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2390 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 )
2392 int i,k;
2393 int initGlyph, finaGlyph;
2394 INT dirR, dirL;
2395 BYTE *spaces;
2397 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2398 memset(spaces,0,cGlyphs);
2400 if (!psa->fLogicalOrder && psa->fRTL)
2402 initGlyph = cGlyphs-1;
2403 finaGlyph = 0;
2404 dirR = 1;
2405 dirL = -1;
2407 else
2409 initGlyph = 0;
2410 finaGlyph = cGlyphs-1;
2411 dirR = -1;
2412 dirL = 1;
2415 for (i = 0; i < cGlyphs; i++)
2417 for (k = 0; k < cChars; k++)
2418 if (pwLogClust[k] == i)
2420 if (pwcChars[k] == 0x0020)
2421 spaces[i] = 1;
2425 for (i = 0; i < cGlyphs; i++)
2427 int char_index[20];
2428 int char_count = 0;
2429 BOOL isInit, isFinal;
2431 for (k = 0; k < cChars; k++)
2433 if (pwLogClust[k] == i)
2435 char_index[char_count] = k;
2436 char_count++;
2440 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2441 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2443 if (char_count == 0)
2444 continue;
2446 if (char_count == 1)
2448 if (pwcChars[char_index[0]] == 0x0020) /* space */
2450 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2451 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2453 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2454 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2455 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2457 if (!isInit && !isFinal)
2458 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2459 else if (isInit)
2460 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2461 else
2462 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2464 else if (!isInit)
2466 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2467 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2468 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2469 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2470 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2471 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2472 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2473 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2474 else
2475 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2477 else if (!isInit && !isFinal)
2478 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2479 else
2480 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2482 else if (char_count == 2)
2484 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2485 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2486 else if (!isInit)
2487 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2488 else
2489 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2491 else if (!isInit && !isFinal)
2492 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2493 else
2494 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2497 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2498 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2499 HeapFree(GetProcessHeap(),0,spaces);
2502 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 )
2504 int i,k;
2505 int finaGlyph;
2506 INT dirL;
2507 BYTE *spaces;
2509 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2510 memset(spaces,0,cGlyphs);
2512 if (!psa->fLogicalOrder && psa->fRTL)
2514 finaGlyph = 0;
2515 dirL = -1;
2517 else
2519 finaGlyph = cGlyphs-1;
2520 dirL = 1;
2523 for (i = 0; i < cGlyphs; i++)
2525 for (k = 0; k < cChars; k++)
2526 if (pwLogClust[k] == i)
2528 if (pwcChars[k] == 0x0020)
2529 spaces[i] = 1;
2533 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2535 for (i = 0; i < cGlyphs; i++)
2537 int char_index[20];
2538 int char_count = 0;
2540 for (k = 0; k < cChars; k++)
2542 if (pwLogClust[k] == i)
2544 char_index[char_count] = k;
2545 char_count++;
2549 if (char_count == 0)
2550 continue;
2552 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2554 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2555 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2557 else if (i == finaGlyph)
2558 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2559 else
2560 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2562 /* handle Thai SARA AM (U+0E33) differently than GDEF */
2563 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
2564 pGlyphProp[i].sva.fClusterStart = 0;
2567 HeapFree(GetProcessHeap(),0,spaces);
2568 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2570 /* Do not allow justification between marks and their base */
2571 for (i = 0; i < cGlyphs; i++)
2573 if (!pGlyphProp[i].sva.fClusterStart)
2574 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2578 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)
2580 int i,k;
2582 for (i = 0; i < cGlyphs; i++)
2584 int char_index[20];
2585 int char_count = 0;
2587 for (k = 0; k < cChars; k++)
2589 if (pwLogClust[k] == i)
2591 char_index[char_count] = k;
2592 char_count++;
2596 if (char_count == 0)
2597 continue;
2599 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2601 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2602 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2604 else
2605 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2607 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2608 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2611 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)
2613 int i,k;
2615 for (i = 0; i < cGlyphs; i++)
2617 int char_index[20];
2618 int char_count = 0;
2620 for (k = 0; k < cChars; k++)
2622 if (pwLogClust[k] == i)
2624 char_index[char_count] = k;
2625 char_count++;
2629 if (char_count == 0)
2630 continue;
2632 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2634 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2635 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2637 else
2638 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2640 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2641 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2643 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2644 for (i = 0; i < cGlyphs; i++)
2646 if (!pGlyphProp[i].sva.fClusterStart)
2648 pGlyphProp[i].sva.fDiacritic = 0;
2649 pGlyphProp[i].sva.fZeroWidth = 0;
2654 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)
2656 int i,k;
2658 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2659 for (i = 0; i < cGlyphs; i++)
2661 int char_index[20];
2662 int char_count = 0;
2664 for (k = 0; k < cChars; k++)
2666 if (pwLogClust[k] == i)
2668 char_index[char_count] = k;
2669 char_count++;
2673 if (override_gsub)
2675 /* Most indic scripts do not set fDiacritic or fZeroWidth */
2676 pGlyphProp[i].sva.fDiacritic = FALSE;
2677 pGlyphProp[i].sva.fZeroWidth = FALSE;
2680 if (char_count == 0)
2681 continue;
2683 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2685 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2686 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2688 else
2689 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2691 pGlyphProp[i].sva.fClusterStart = 0;
2692 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2693 switch (lexical(pwcChars[char_index[k]]))
2695 case lex_Matra_pre:
2696 case lex_Matra_post:
2697 case lex_Matra_above:
2698 case lex_Matra_below:
2699 case lex_Modifier:
2700 case lex_Halant:
2701 break;
2702 case lex_ZWJ:
2703 case lex_ZWNJ:
2704 /* check for dangling joiners */
2705 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
2706 pGlyphProp[i].sva.fClusterStart = 1;
2707 else
2708 k = char_count;
2709 break;
2710 default:
2711 pGlyphProp[i].sva.fClusterStart = 1;
2712 break;
2716 if (use_syllables)
2718 IndicSyllable *syllables = NULL;
2719 int syllable_count = 0;
2720 BOOL modern = get_GSUB_Indic2(psa, psc);
2722 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
2724 for (i = 0; i < syllable_count; i++)
2726 int j;
2727 WORD g = pwLogClust[syllables[i].start];
2728 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
2730 if (pwLogClust[j] != g)
2732 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
2733 pwLogClust[j] = g;
2738 HeapFree(GetProcessHeap(), 0, syllables);
2741 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2744 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 )
2746 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
2749 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 )
2751 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
2754 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 )
2756 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
2759 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 )
2761 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
2764 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 )
2766 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
2769 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 )
2771 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
2774 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 )
2776 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
2779 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 )
2781 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
2784 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 )
2786 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
2789 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 )
2791 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
2794 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 )
2796 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
2799 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)
2801 if (ShapingData[psa->eScript].charGlyphPropProc)
2802 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2803 else
2804 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2807 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2809 if (!psc->GSUB_Table)
2810 psc->GSUB_Table = load_gsub_table(hdc);
2812 if (ShapingData[psa->eScript].contextProc)
2813 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2816 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)
2818 int i;
2819 INT dirL;
2821 if (!rpRangeProperties)
2822 return;
2824 if (!psc->GSUB_Table)
2825 psc->GSUB_Table = load_gsub_table(hdc);
2827 if (!psc->GSUB_Table)
2828 return;
2830 if (!psa->fLogicalOrder && psa->fRTL)
2831 dirL = -1;
2832 else
2833 dirL = 1;
2835 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
2837 if (rpRangeProperties->potfRecords[i].lParameter > 0)
2838 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
2842 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
2844 const TEXTRANGE_PROPERTIES *rpRangeProperties;
2845 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
2847 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
2850 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
2852 LoadedFeature *feature;
2853 int i;
2855 if (!ShapingData[psa->eScript].requiredFeatures)
2856 return S_OK;
2858 if (!psc->GSUB_Table)
2859 psc->GSUB_Table = load_gsub_table(hdc);
2861 /* we need to have at least one of the required features */
2862 i = 0;
2863 while (ShapingData[psa->eScript].requiredFeatures[i])
2865 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
2866 if (feature)
2867 return S_OK;
2868 i++;
2871 return USP_E_SCRIPT_NOT_IN_FONT;
2874 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
2875 SCRIPT_ANALYSIS *psa, int cMaxTags,
2876 OPENTYPE_TAG *pScriptTags, int *pcTags)
2878 HRESULT hr;
2879 OPENTYPE_TAG searching = 0x00000000;
2881 if (!psc->GSUB_Table)
2882 psc->GSUB_Table = load_gsub_table(hdc);
2884 if (psa && scriptInformation[psa->eScript].scriptTag)
2885 searching = scriptInformation[psa->eScript].scriptTag;
2887 hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL);
2888 if (FAILED(hr))
2889 *pcTags = 0;
2890 return hr;
2893 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
2894 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2895 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
2896 int *pcTags)
2898 HRESULT hr;
2899 OPENTYPE_TAG searching = 0x00000000;
2900 BOOL fellback = FALSE;
2902 if (!psc->GSUB_Table)
2903 psc->GSUB_Table = load_gsub_table(hdc);
2905 if (psa && psc->userLang != 0)
2906 searching = psc->userLang;
2908 hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL);
2909 if (FAILED(hr))
2911 fellback = TRUE;
2912 hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL);
2915 if (FAILED(hr) || fellback)
2916 *pcTags = 0;
2917 if (SUCCEEDED(hr) && fellback && psa)
2918 hr = E_INVALIDARG;
2919 return hr;
2922 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
2923 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2924 OPENTYPE_TAG tagLangSys, int cMaxTags,
2925 OPENTYPE_TAG *pFeatureTags, int *pcTags)
2927 HRESULT hr;
2928 BOOL filter = FALSE;
2930 if (!psc->GSUB_Table)
2931 psc->GSUB_Table = load_gsub_table(hdc);
2933 if (psa && scriptInformation[psa->eScript].scriptTag)
2935 FIXME("Filtering not implemented\n");
2936 filter = TRUE;
2939 hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL);
2941 if (FAILED(hr))
2942 *pcTags = 0;
2943 return hr;