regedit: An English (United States) spelling fix.
[wine/multimedia.git] / dlls / usp10 / shape.c
blobefb9b7139bfab70e6ba5304776067393cfe19ba2
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 ethiopic_features[] =
362 { MS_MAKE_TAG('c','c','m','p'), 1},
363 { MS_MAKE_TAG('l','o','c','l'), 1},
364 { MS_MAKE_TAG('c','a','l','t'), 1},
365 { MS_MAKE_TAG('l','i','g','a'), 1},
368 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
370 { MS_MAKE_TAG('c','c','m','p'), 1},
371 { MS_MAKE_TAG('l','o','c','l'), 1},
372 { MS_MAKE_TAG('c','a','l','t'), 1},
373 { MS_MAKE_TAG('r','l','i','g'), 1},
376 typedef struct ScriptShapeDataTag {
377 TEXTRANGE_PROPERTIES defaultTextRange;
378 const char** requiredFeatures;
379 OPENTYPE_TAG newOtTag;
380 ContextualShapingProc contextProc;
381 ShapeCharGlyphPropProc charGlyphPropProc;
382 } ScriptShapeData;
384 /* in order of scripts */
385 static const ScriptShapeData ShapingData[] =
387 {{ standard_features, 2}, NULL, 0, NULL, NULL},
388 {{ latin_features, 2}, NULL, 0, NULL, NULL},
389 {{ latin_features, 2}, NULL, 0, NULL, NULL},
390 {{ latin_features, 2}, NULL, 0, NULL, NULL},
391 {{ standard_features, 2}, NULL, 0, NULL, NULL},
392 {{ latin_features, 2}, NULL, 0, NULL, NULL},
393 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
394 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
395 {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
396 {{ syriac_features, 4}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
397 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
398 {{ NULL, 0}, NULL, 0, NULL, ShapeCharGlyphProp_None},
399 {{ standard_features, 2}, NULL, 0, NULL, NULL},
400 {{ standard_features, 2}, NULL, 0, NULL, NULL},
401 {{ standard_features, 2}, NULL, 0, NULL, NULL},
402 {{ standard_features, 2}, NULL, 0, NULL, NULL},
403 {{ sinhala_features, 3}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
404 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
405 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
406 {{ phags_features, 3}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
407 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
408 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
409 {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
410 {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
411 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
412 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
413 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
414 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
415 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
416 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
417 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
418 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
419 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
420 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
421 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
422 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
423 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
424 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
425 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
426 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
427 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
428 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
429 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
430 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
431 {{ standard_features, 2}, NULL, 0, NULL, NULL},
432 {{ latin_features, 2}, NULL, 0, NULL, NULL},
433 {{ standard_features, 2}, NULL, 0, NULL, NULL},
434 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
435 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
436 {{ standard_features, 2}, NULL, 0, NULL, NULL},
437 {{ standard_features, 2}, NULL, 0, NULL, NULL},
438 {{ standard_features, 2}, NULL, 0, NULL, NULL},
439 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
440 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
441 {{ NULL, 0}, NULL, 0, NULL, NULL},
442 {{ NULL, 0}, NULL, 0, NULL, NULL},
443 {{ NULL, 0}, NULL, 0, NULL, NULL},
444 {{ NULL, 0}, NULL, 0, NULL, NULL},
445 {{ NULL, 0}, NULL, 0, NULL, NULL},
446 {{ NULL, 0}, NULL, 0, NULL, NULL},
447 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
448 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
449 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
450 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
451 {{ NULL, 0}, NULL, 0, NULL, NULL},
452 {{ NULL, 0}, NULL, 0, NULL, NULL},
453 {{ NULL, 0}, NULL, 0, NULL, NULL},
454 {{ NULL, 0}, NULL, 0, NULL, NULL},
455 {{ NULL, 0}, NULL, 0, NULL, NULL},
456 {{ NULL, 0}, NULL, 0, NULL, NULL},
457 {{ NULL, 0}, NULL, 0, NULL, NULL},
458 {{ NULL, 0}, NULL, 0, NULL, NULL},
459 {{ NULL, 0}, NULL, 0, NULL, NULL},
460 {{ NULL, 0}, NULL, 0, NULL, NULL},
461 {{ NULL, 0}, NULL, 0, NULL, NULL},
462 {{ NULL, 0}, NULL, 0, NULL, NULL},
463 {{ NULL, 0}, NULL, 0, NULL, NULL},
464 {{ NULL, 0}, NULL, 0, NULL, NULL},
465 {{ NULL, 0}, NULL, 0, NULL, NULL},
466 {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
467 {{ latin_features, 2}, NULL, 0, NULL, NULL},
468 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
471 extern scriptData scriptInformation[];
473 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
475 int i;
476 int out_index = GSUB_E_NOGLYPH;
478 TRACE("%i lookups\n", feature->lookup_count);
479 for (i = 0; i < feature->lookup_count; i++)
481 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
482 if (out_index != GSUB_E_NOGLYPH)
483 break;
485 if (out_index == GSUB_E_NOGLYPH)
486 TRACE("lookups found no glyphs\n");
487 else
489 int out2;
490 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
491 if (out2!=GSUB_E_NOGLYPH)
492 out_index = out2;
494 return out_index;
497 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
499 UINT charset;
501 if (psc->userScript != 0)
503 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
504 return ShapingData[psa->eScript].newOtTag;
505 else
506 return psc->userScript;
509 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
510 return ShapingData[psa->eScript].newOtTag;
512 if (scriptInformation[psa->eScript].scriptTag)
513 return scriptInformation[psa->eScript].scriptTag;
516 * fall back to the font charset
518 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
519 switch (charset)
521 case ANSI_CHARSET:
522 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
523 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
524 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
525 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
526 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
527 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
528 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
529 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
530 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
531 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
532 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
533 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
534 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
535 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
536 default: return MS_MAKE_TAG('l','a','t','n');
540 static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
542 LoadedFeature *feature = NULL;
544 if (psc->GSUB_Table)
546 int attempt = 2;
547 OPENTYPE_TAG tags;
548 OPENTYPE_TAG language;
549 OPENTYPE_TAG script;
550 int cTags;
554 script = get_opentype_script(hdc,psa,psc,(attempt==2));
555 if (psc->userLang != 0)
556 language = psc->userLang;
557 else
558 language = MS_MAKE_TAG('d','f','l','t');
559 attempt--;
561 OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
563 } while(attempt && !feature);
565 /* try in the default (latin) table */
566 if (!feature)
567 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);
570 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
571 return feature;
574 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)
576 LoadedFeature *feature;
578 feature = load_GSUB_feature(hdc, psa, psc, feat);
579 if (!feature)
580 return GSUB_E_NOFEATURE;
582 TRACE("applying feature %s\n",feat);
583 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
586 static VOID *load_gsub_table(HDC hdc)
588 VOID* GSUB_Table = NULL;
589 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
590 if (length != GDI_ERROR)
592 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
593 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
594 TRACE("Loaded GSUB table of %i bytes\n",length);
596 return GSUB_Table;
599 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)
601 WORD *glyphs;
602 INT glyph_count = count;
603 INT rc;
605 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
606 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
607 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
608 if (rc > GSUB_E_NOGLYPH)
609 rc = count - glyph_count;
610 else
611 rc = 0;
613 HeapFree(GetProcessHeap(),0,glyphs);
614 return rc;
617 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
619 int i;
621 for (i = 0; i < cGlyphs; i++)
623 if (!pGlyphProp[i].sva.fClusterStart)
625 int j;
626 for (j = 0; j < cChars; j++)
628 if (pwLogClust[j] == i)
630 int k = j;
631 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
632 k-=1;
633 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
634 pwLogClust[j] = pwLogClust[k];
641 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
643 if (changeCount == 0)
644 return;
645 else
647 int i;
648 int target_glyph = nextIndex - write_dir;
649 int seeking_glyph;
650 int target_index = -1;
651 int replacing_glyph = -1;
652 int changed = 0;
653 int top_logclust = 0;
655 if (changeCount > 0)
657 if (write_dir > 0)
658 target_glyph = nextIndex - changeCount;
659 else
660 target_glyph = nextIndex + (changeCount + 1);
663 seeking_glyph = target_glyph;
664 for (i = 0; i < chars; i++)
665 if (pwLogClust[i] > top_logclust)
666 top_logclust = pwLogClust[i];
668 do {
669 if (write_dir > 0)
670 for (i = 0; i < chars; i++)
672 if (pwLogClust[i] == seeking_glyph)
674 target_index = i;
675 break;
678 else
679 for (i = chars - 1; i >= 0; i--)
681 if (pwLogClust[i] == seeking_glyph)
683 target_index = i;
684 break;
687 if (target_index == -1)
688 seeking_glyph ++;
690 while (target_index == -1 && seeking_glyph <= top_logclust);
692 if (target_index == -1)
694 ERR("Unable to find target glyph\n");
695 return;
698 if (changeCount < 0)
700 /* merge glyphs */
701 for(i = target_index; i < chars && i >= 0; i+=write_dir)
703 if (pwLogClust[i] == target_glyph)
704 continue;
705 if(pwLogClust[i] == replacing_glyph)
706 pwLogClust[i] = target_glyph;
707 else
709 changed--;
710 if (changed >= changeCount)
712 replacing_glyph = pwLogClust[i];
713 pwLogClust[i] = target_glyph;
715 else
716 break;
720 /* renumber trailing indexes*/
721 for(i = target_index; i < chars && i >= 0; i+=write_dir)
723 if (pwLogClust[i] != target_glyph)
724 pwLogClust[i] += changeCount;
727 else
729 for(i = target_index; i < chars && i >= 0; i+=write_dir)
730 pwLogClust[i] += changeCount;
735 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 )
737 if (psc->GSUB_Table)
739 LoadedFeature *feature;
740 int lookup_index;
742 feature = load_GSUB_feature(hdc, psa, psc, feat);
743 if (!feature)
744 return GSUB_E_NOFEATURE;
746 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
747 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
749 int i;
751 if (write_dir > 0)
752 i = 0;
753 else
754 i = *pcGlyphs-1;
755 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
756 while(i < *pcGlyphs && i >= 0)
758 INT nextIndex;
759 INT prevCount = *pcGlyphs;
761 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
762 if (*pcGlyphs != prevCount)
764 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
765 i = nextIndex;
767 else
768 i+=write_dir;
771 return *pcGlyphs;
773 return GSUB_E_NOFEATURE;
776 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
778 OPENTYPE_TAG tag;
779 HRESULT hr;
780 int count = 0;
782 hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL);
784 return(SUCCEEDED(hr));
787 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
789 if (i + delta < 0)
790 return 0;
791 if ( i+ delta >= cchLen)
792 return 0;
794 i += delta;
796 return chars[i];
799 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
801 if (i + delta < 0)
803 if (psa->fLinkBefore)
804 return jtR;
805 else
806 return jtU;
808 if ( i+ delta >= cchLen)
810 if (psa->fLinkAfter)
811 return jtL;
812 else
813 return jtU;
816 i += delta;
818 if (context_type[i] == jtT)
819 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
820 else
821 return context_type[i];
824 static inline BOOL right_join_causing(CHAR joining_type)
826 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
829 static inline BOOL left_join_causing(CHAR joining_type)
831 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
834 static inline BOOL word_break_causing(WCHAR chr)
836 /* we are working within a string of characters already guareented to
837 be within one script, Syriac, so we do not worry about any character
838 other than the space character outside of that range */
839 return (chr == 0 || chr == 0x20 );
843 * ContextualShape_Arabic
845 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
847 CHAR *context_type;
848 INT *context_shape;
849 INT dirR, dirL;
850 int i;
852 if (*pcGlyphs != cChars)
854 ERR("Number of Glyphs and Chars need to match at the beginning\n");
855 return;
858 if (!psa->fLogicalOrder && psa->fRTL)
860 dirR = 1;
861 dirL = -1;
863 else
865 dirR = -1;
866 dirL = 1;
869 if (!psc->GSUB_Table)
870 psc->GSUB_Table = load_gsub_table(hdc);
872 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
873 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
875 for (i = 0; i < cChars; i++)
876 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
878 for (i = 0; i < cChars; i++)
880 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
881 context_shape[i] = Xr;
882 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
883 context_shape[i] = Xl;
884 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)))
885 context_shape[i] = Xm;
886 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
887 context_shape[i] = Xr;
888 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
889 context_shape[i] = Xl;
890 else
891 context_shape[i] = Xn;
894 /* Contextual Shaping */
895 i = 0;
896 while(i < *pcGlyphs)
898 BOOL shaped = FALSE;
900 if (psc->GSUB_Table)
902 INT nextIndex;
903 INT prevCount = *pcGlyphs;
904 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
905 if (nextIndex > GSUB_E_NOGLYPH)
907 i = nextIndex;
908 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
910 shaped = (nextIndex > GSUB_E_NOGLYPH);
913 if (!shaped)
915 if (context_shape[i] == Xn)
917 WORD newGlyph = pwOutGlyphs[i];
918 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
920 /* fall back to presentation form B */
921 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
922 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
923 pwOutGlyphs[i] = newGlyph;
926 i++;
930 HeapFree(GetProcessHeap(),0,context_shape);
931 HeapFree(GetProcessHeap(),0,context_type);
935 * ContextualShape_Syriac
938 #define ALAPH 0x710
939 #define DALATH 0x715
940 #define RISH 0x72A
942 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
944 CHAR *context_type;
945 INT *context_shape;
946 INT dirR, dirL;
947 int i;
949 if (*pcGlyphs != cChars)
951 ERR("Number of Glyphs and Chars need to match at the beginning\n");
952 return;
955 if (!psa->fLogicalOrder && psa->fRTL)
957 dirR = 1;
958 dirL = -1;
960 else
962 dirR = -1;
963 dirL = 1;
966 if (!psc->GSUB_Table)
967 psc->GSUB_Table = load_gsub_table(hdc);
969 if (!psc->GSUB_Table)
970 return;
972 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
973 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
975 for (i = 0; i < cChars; i++)
976 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
978 for (i = 0; i < cChars; i++)
980 if (pwcChars[i] == ALAPH)
982 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
984 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
985 context_shape[i] = Afj;
986 else if ( rchar != DALATH && rchar != RISH &&
987 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
988 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
989 context_shape[i] = Afn;
990 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
991 context_shape[i] = Afx;
992 else
993 context_shape[i] = Xn;
995 else if (context_type[i] == jtR &&
996 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
997 context_shape[i] = Xr;
998 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
999 context_shape[i] = Xl;
1000 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)))
1001 context_shape[i] = Xm;
1002 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1003 context_shape[i] = Xr;
1004 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1005 context_shape[i] = Xl;
1006 else
1007 context_shape[i] = Xn;
1010 /* Contextual Shaping */
1011 i = 0;
1012 while(i < *pcGlyphs)
1014 INT nextIndex;
1015 INT prevCount = *pcGlyphs;
1016 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1017 if (nextIndex > GSUB_E_NOGLYPH)
1019 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1020 i = nextIndex;
1022 else
1023 i++;
1026 HeapFree(GetProcessHeap(),0,context_shape);
1027 HeapFree(GetProcessHeap(),0,context_type);
1031 * ContextualShape_Phags_pa
1034 #define phags_pa_CANDRABINDU 0xA873
1035 #define phags_pa_START 0xA840
1036 #define phags_pa_END 0xA87F
1038 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1040 INT *context_shape;
1041 INT dirR, dirL;
1042 int i;
1044 if (*pcGlyphs != cChars)
1046 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1047 return;
1050 if (!psa->fLogicalOrder && psa->fRTL)
1052 dirR = 1;
1053 dirL = -1;
1055 else
1057 dirR = -1;
1058 dirL = 1;
1061 if (!psc->GSUB_Table)
1062 psc->GSUB_Table = load_gsub_table(hdc);
1064 if (!psc->GSUB_Table)
1065 return;
1067 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1069 for (i = 0; i < cChars; i++)
1071 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1073 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1074 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1075 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1076 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1078 if (jrchar && jlchar)
1079 context_shape[i] = Xm;
1080 else if (jrchar)
1081 context_shape[i] = Xr;
1082 else if (jlchar)
1083 context_shape[i] = Xl;
1084 else
1085 context_shape[i] = Xn;
1087 else
1088 context_shape[i] = -1;
1091 /* Contextual Shaping */
1092 i = 0;
1093 while(i < *pcGlyphs)
1095 if (context_shape[i] >= 0)
1097 INT nextIndex;
1098 INT prevCount = *pcGlyphs;
1099 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1100 if (nextIndex > GSUB_E_NOGLYPH)
1102 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1103 i = nextIndex;
1105 else
1106 i++;
1108 else
1109 i++;
1112 HeapFree(GetProcessHeap(),0,context_shape);
1115 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1117 int i;
1119 /* Replace */
1120 pwOutChars[cWalk] = replacements[0];
1121 cWalk=cWalk+1;
1123 /* Insert */
1124 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1126 int j;
1127 for (j = *pcChars; j > cWalk; j--)
1128 pwOutChars[j] = pwOutChars[j-1];
1129 *pcChars= *pcChars+1;
1130 pwOutChars[cWalk] = replacements[i];
1131 cWalk = cWalk+1;
1135 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1137 int i;
1138 int cWalk;
1140 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1142 for (i = 0; vowels[i].base != 0x0; i++)
1144 if (pwOutChars[cWalk] == vowels[i].base)
1146 int o = 0;
1147 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1148 if (vowels[i].parts[1]) { cWalk++; o++; }
1149 if (vowels[i].parts[2]) { cWalk++; o++; }
1150 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1151 break;
1157 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1159 int i;
1160 int offset = 0;
1161 int cWalk;
1163 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1165 for (i = 0; consonants[i].output!= 0x0; i++)
1167 int j;
1168 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1169 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1170 break;
1172 if (consonants[i].parts[j]==0x0) /* matched all */
1174 int k;
1175 j--;
1176 pwOutChars[cWalk] = consonants[i].output;
1177 for(k = cWalk+1; k < *pcChars - j; k++)
1178 pwOutChars[k] = pwOutChars[k+j];
1179 *pcChars = *pcChars - j;
1180 for (k = j ; k > 0; k--)
1181 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1182 offset += j;
1183 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1184 pwLogClust[k]--;
1185 break;
1188 cWalk++;
1192 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1194 if (s->ralf >= 0)
1196 int j;
1197 WORD Ra = pwChar[s->start];
1198 WORD H = pwChar[s->start+1];
1200 TRACE("Doing reorder of Ra to %i\n",s->base);
1201 for (j = s->start; j < s->base-1; j++)
1202 pwChar[j] = pwChar[j+2];
1203 pwChar[s->base-1] = Ra;
1204 pwChar[s->base] = H;
1206 s->ralf = s->base-1;
1207 s->base -= 2;
1211 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1213 if (s->ralf >= 0)
1215 int j,loc;
1216 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1217 WORD Ra = pwChar[s->start];
1218 WORD H = pwChar[s->start+1];
1219 for (loc = s->end; loc > stop; loc--)
1220 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1221 break;
1223 TRACE("Doing reorder of Ra to %i\n",loc);
1224 for (j = s->start; j < loc-1; j++)
1225 pwChar[j] = pwChar[j+2];
1226 pwChar[loc-1] = Ra;
1227 pwChar[loc] = H;
1229 s->ralf = loc-1;
1230 s->base -= 2;
1231 if (s->blwf >= 0) s->blwf -= 2;
1232 if (s->pref >= 0) s->pref -= 2;
1236 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1238 if (s->ralf >= 0)
1240 int j;
1241 WORD Ra = pwChar[s->start];
1242 WORD H = pwChar[s->start+1];
1244 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1245 for (j = s->start; j < s->end-1; j++)
1246 pwChar[j] = pwChar[j+2];
1247 pwChar[s->end-1] = Ra;
1248 pwChar[s->end] = H;
1250 s->ralf = s->end-1;
1251 s->base -= 2;
1252 if (s->blwf >= 0) s->blwf -= 2;
1253 if (s->pref >= 0) s->pref -= 2;
1257 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1259 int i;
1261 /* reorder Matras */
1262 if (s->end > s->base)
1264 for (i = 1; i <= s->end-s->base; i++)
1266 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1268 int j;
1269 WCHAR c = pwChar[s->base+i];
1270 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1271 for (j = s->base+i; j > s->base; j--)
1272 pwChar[j] = pwChar[j-1];
1273 pwChar[s->base] = c;
1275 if (s->ralf >= s->base) s->ralf++;
1276 if (s->blwf >= s->base) s->blwf++;
1277 if (s->pref >= s->base) s->pref++;
1278 s->base ++;
1284 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1286 int i;
1288 /* reorder Matras */
1289 if (s->end > s->base)
1291 for (i = 1; i <= s->end-s->base; i++)
1293 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1295 int j;
1296 WCHAR c = pwChar[s->base+i];
1297 TRACE("Doing reorder of %x to %i\n",c,s->start);
1298 for (j = s->base+i; j > s->start; j--)
1299 pwChar[j] = pwChar[j-1];
1300 pwChar[s->start] = c;
1302 if (s->ralf >= 0) s->ralf++;
1303 if (s->blwf >= 0) s->blwf++;
1304 if (s->pref >= 0) s->pref++;
1305 s->base ++;
1311 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1313 if (s->blwf >= 0 && g->blwf > g->base)
1315 int j,loc;
1316 int g_offset;
1317 for (loc = s->end; loc > s->blwf; loc--)
1318 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1319 break;
1321 g_offset = (loc - s->blwf) - 1;
1323 if (loc != s->blwf)
1325 WORD blwf = glyphs[g->blwf];
1326 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1327 /* do not care about the pwChar array anymore, just the glyphs */
1328 for (j = 0; j < g_offset; j++)
1329 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1330 glyphs[g->blwf + g_offset] = blwf;
1335 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1337 int i;
1339 /* reorder previously moved Matras to correct position*/
1340 for (i = s->start; i < s->base; i++)
1342 if (lexical(pwChar[i]) == lex_Matra_pre)
1344 int j;
1345 int g_start = g->start + i - s->start;
1346 if (g_start < g->base -1 )
1348 WCHAR og = glyphs[g_start];
1349 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1350 for (j = g_start; j < g->base-1; j++)
1351 glyphs[j] = glyphs[j+1];
1352 glyphs[g->base-1] = og;
1358 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1360 if (s->pref >= 0 && g->pref > g->base)
1362 int j;
1363 WCHAR og = glyphs[g->pref];
1364 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1365 for (j = g->pref; j > g->base; j--)
1366 glyphs[j] = glyphs[j-1];
1367 glyphs[g->base] = og;
1371 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1373 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1374 if (s->start == s->base && s->base == s->end) return;
1375 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1377 Reorder_Ra_follows_base(pwChar, s, lexical);
1378 Reorder_Matra_precede_base(pwChar, s, lexical);
1381 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1383 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1384 if (s->start == s->base && s->base == s->end) return;
1385 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1387 Reorder_Ra_follows_matra(pwChar, s, lexical);
1388 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1391 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1393 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1394 if (s->start == s->base && s->base == s->end) return;
1395 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1397 Reorder_Ra_follows_base(pwChar, s, lexical);
1398 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1401 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1403 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1404 if (s->start == s->base && s->base == s->end) return;
1405 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1407 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1408 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1411 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1413 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1414 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1415 if (s->start == s->base && s->base == s->end) return;
1416 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1418 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1421 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1423 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1424 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1425 if (s->start == s->base && s->base == s->end) return;
1426 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1428 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1429 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1433 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1435 if (shift == 0)
1436 return;
1438 if (glyph_index->start > index)
1439 glyph_index->start += shift;
1440 if (glyph_index->base > index)
1441 glyph_index->base+= shift;
1442 if (glyph_index->end > index)
1443 glyph_index->end+= shift;
1444 if (glyph_index->ralf > index)
1445 glyph_index->ralf+= shift;
1446 if (glyph_index->blwf > index)
1447 glyph_index->blwf+= shift;
1448 if (glyph_index->pref > index)
1449 glyph_index->pref+= shift;
1452 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 )
1454 int index = glyph_index->start;
1456 if (!feature)
1457 return;
1459 while(index <= glyph_index->end)
1461 INT nextIndex;
1462 INT prevCount = *pcGlyphs;
1463 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1464 if (nextIndex > GSUB_E_NOGLYPH)
1466 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1467 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1468 index = nextIndex;
1470 else
1471 index++;
1475 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1477 int i = 0;
1478 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)))))
1479 i++;
1480 if (index + i <= end-1)
1481 return index + i;
1482 else
1483 return -1;
1486 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)
1488 INT index, nextIndex;
1489 INT count,g_offset;
1491 count = syllable->base - syllable->start;
1493 g_offset = 0;
1494 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1495 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1497 INT prevCount = *pcGlyphs;
1498 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1499 if (nextIndex > GSUB_E_NOGLYPH)
1501 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1502 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1503 g_offset += (*pcGlyphs - prevCount);
1506 index+=2;
1507 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1511 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)
1513 INT nextIndex;
1514 INT prevCount = *pcGlyphs;
1516 if (syllable->ralf >= 0)
1518 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1519 if (nextIndex > GSUB_E_NOGLYPH)
1521 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1522 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1527 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1529 int i = 0;
1530 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1531 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1532 is_consonant(lexical(pwChars[index+i+1])))))
1533 i++;
1534 if (index + i <= end-1)
1535 return index+i;
1536 else
1537 return -1;
1540 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)
1542 INT index, nextIndex;
1543 INT count, g_offset=0;
1544 INT ralf = syllable->ralf;
1546 count = syllable->end - syllable->base;
1548 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
1550 while (index >= 0)
1552 INT prevCount = *pcGlyphs;
1553 if (ralf >=0 && ralf < index)
1555 g_offset--;
1556 ralf = -1;
1559 if (!modern)
1561 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1562 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1563 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1566 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
1567 if (nextIndex > GSUB_E_NOGLYPH)
1569 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1570 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
1571 g_offset += (*pcGlyphs - prevCount);
1573 else if (!modern)
1575 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1576 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1577 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1580 index+=2;
1581 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
1585 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)
1587 int c;
1588 int overall_shift = 0;
1589 LoadedFeature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
1590 LoadedFeature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
1591 LoadedFeature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
1592 LoadedFeature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
1593 LoadedFeature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
1594 LoadedFeature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
1595 LoadedFeature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
1596 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
1597 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
1598 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
1599 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
1600 IndicSyllable glyph_indexs;
1602 for (c = 0; c < syllable_count; c++)
1604 int old_end;
1605 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
1606 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
1607 old_end = glyph_indexs.end;
1609 if (locl)
1611 TRACE("applying feature locl\n");
1612 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
1614 if (nukt)
1616 TRACE("applying feature nukt\n");
1617 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
1619 if (akhn)
1621 TRACE("applying feature akhn\n");
1622 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
1625 if (rphf)
1626 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
1627 if (rkrf)
1629 TRACE("applying feature rkrf\n");
1630 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
1632 if (pref)
1633 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
1634 if (blwf)
1636 if (!modern)
1637 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
1639 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
1642 if (half)
1643 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
1644 if (pstf)
1646 TRACE("applying feature pstf\n");
1647 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
1649 if (vatu)
1651 TRACE("applying feature vatu\n");
1652 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
1654 if (cjct)
1656 TRACE("applying feature cjct\n");
1657 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
1660 if (second_reorder)
1661 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
1663 overall_shift += glyph_indexs.end - old_end;
1667 static inline int unicode_lex(WCHAR c)
1669 int type;
1671 if (!c) return lex_Generic;
1672 if (c == 0x200D) return lex_ZWJ;
1673 if (c == 0x200C) return lex_ZWNJ;
1674 if (c == 0x00A0) return lex_NBSP;
1676 type = get_table_entry( indic_syllabic_table, c );
1678 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
1680 switch( type )
1682 case 0x0d07: /* Unknown */
1683 case 0x0e07: /* Unknwon */
1684 default: return lex_Generic;
1685 case 0x0001:
1686 case 0x0002:
1687 case 0x0011:
1688 case 0x0012:
1689 case 0x0013:
1690 case 0x0014: return lex_Modifier;
1691 case 0x0003:
1692 case 0x0009:
1693 case 0x000a:
1694 case 0x000b:
1695 case 0x000d:
1696 case 0x000e:
1697 case 0x000f:
1698 case 0x0010: return lex_Consonant;
1699 case 0x0004: return lex_Nukta;
1700 case 0x0005: return lex_Halant;
1701 case 0x0006:
1702 case 0x0008: return lex_Vowel;
1703 case 0x0007:
1704 case 0x0107: return lex_Matra_post;
1705 case 0x0207:
1706 case 0x0307: return lex_Matra_pre;
1707 case 0x0807:
1708 case 0x0907:
1709 case 0x0a07:
1710 case 0x0b07:
1711 case 0x0c07:
1712 case 0x0407: return lex_Composed_Vowel;
1713 case 0x0507: return lex_Matra_above;
1714 case 0x0607: return lex_Matra_below;
1715 case 0x000c: return lex_Ra;
1719 static int sinhala_lex(WCHAR c)
1721 switch (c)
1723 case 0x0DDA:
1724 case 0x0DDD:
1725 case 0x0DDC:
1726 case 0x0DDE: return lex_Matra_post;
1727 default:
1728 return unicode_lex(c);
1732 static const VowelComponents Sinhala_vowels[] = {
1733 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
1734 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
1735 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
1736 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
1737 {0x0000, {0x0000,0x0000,0x0}}};
1739 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1741 int cCount = cChars;
1742 int i;
1743 WCHAR *input;
1744 IndicSyllable *syllables = NULL;
1745 int syllable_count = 0;
1747 if (*pcGlyphs != cChars)
1749 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1750 return;
1753 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
1755 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1757 /* Step 1: Decompose multi part vowels */
1758 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
1760 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1762 /* Step 2: Reorder within Syllables */
1763 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
1764 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1766 /* Step 3: Strip dangling joiners */
1767 for (i = 0; i < cCount; i++)
1769 if ((input[i] == 0x200D || input[i] == 0x200C) &&
1770 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
1771 input[i] = 0x0020;
1774 /* Step 4: Base Form application to syllables */
1775 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1776 *pcGlyphs = cCount;
1777 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
1779 HeapFree(GetProcessHeap(),0,input);
1780 HeapFree(GetProcessHeap(),0,syllables);
1783 static int devanagari_lex(WCHAR c)
1785 switch (c)
1787 case 0x0930: return lex_Ra;
1788 default:
1789 return unicode_lex(c);
1793 static const ConsonantComponents Devanagari_consonants[] ={
1794 {{0x0928, 0x093C, 0x00000}, 0x0929},
1795 {{0x0930, 0x093C, 0x00000}, 0x0931},
1796 {{0x0933, 0x093C, 0x00000}, 0x0934},
1797 {{0x0915, 0x093C, 0x00000}, 0x0958},
1798 {{0x0916, 0x093C, 0x00000}, 0x0959},
1799 {{0x0917, 0x093C, 0x00000}, 0x095A},
1800 {{0x091C, 0x093C, 0x00000}, 0x095B},
1801 {{0x0921, 0x093C, 0x00000}, 0x095C},
1802 {{0x0922, 0x093C, 0x00000}, 0x095D},
1803 {{0x092B, 0x093C, 0x00000}, 0x095E},
1804 {{0x092F, 0x093C, 0x00000}, 0x095F}};
1806 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1808 int cCount = cChars;
1809 WCHAR *input;
1810 IndicSyllable *syllables = NULL;
1811 int syllable_count = 0;
1812 BOOL modern = get_GSUB_Indic2(psa, psc);
1814 if (*pcGlyphs != cChars)
1816 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1817 return;
1820 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1821 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1823 /* Step 1: Compose Consonant and Nukta */
1824 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
1825 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1827 /* Step 2: Reorder within Syllables */
1828 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
1829 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1830 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1831 *pcGlyphs = cCount;
1833 /* Step 3: Base Form application to syllables */
1834 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
1836 HeapFree(GetProcessHeap(),0,input);
1837 HeapFree(GetProcessHeap(),0,syllables);
1840 static int bengali_lex(WCHAR c)
1842 switch (c)
1844 case 0x09B0: return lex_Ra;
1845 default:
1846 return unicode_lex(c);
1850 static const VowelComponents Bengali_vowels[] = {
1851 {0x09CB, {0x09C7,0x09BE,0x0000}},
1852 {0x09CC, {0x09C7,0x09D7,0x0000}},
1853 {0x0000, {0x0000,0x0000,0x0000}}};
1855 static const ConsonantComponents Bengali_consonants[] = {
1856 {{0x09A4,0x09CD,0x200D}, 0x09CE},
1857 {{0x09A1,0x09BC,0x0000}, 0x09DC},
1858 {{0x09A2,0x09BC,0x0000}, 0x09DD},
1859 {{0x09AF,0x09BC,0x0000}, 0x09DF},
1860 {{0x0000,0x0000,0x0000}, 0x0000}};
1862 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1864 int cCount = cChars;
1865 WCHAR *input;
1866 IndicSyllable *syllables = NULL;
1867 int syllable_count = 0;
1868 BOOL modern = get_GSUB_Indic2(psa, psc);
1870 if (*pcGlyphs != cChars)
1872 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1873 return;
1876 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
1877 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1879 /* Step 1: Decompose Vowels and Compose Consonents */
1880 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
1881 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
1882 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1884 /* Step 2: Reorder within Syllables */
1885 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
1886 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1887 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1888 *pcGlyphs = cCount;
1890 /* Step 3: Initial form is only applied to the beginning of words */
1891 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
1893 if (cCount == 0 || input[cCount] == 0x0020) /* space */
1895 int index = cCount;
1896 int gCount = 1;
1897 if (index > 0) index++;
1899 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
1903 /* Step 4: Base Form application to syllables */
1904 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
1906 HeapFree(GetProcessHeap(),0,input);
1907 HeapFree(GetProcessHeap(),0,syllables);
1910 static int gurmukhi_lex(WCHAR c)
1912 if (c == 0x0A71)
1913 return lex_Modifier;
1914 else
1915 return unicode_lex(c);
1918 static const ConsonantComponents Gurmukhi_consonants[] = {
1919 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
1920 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
1921 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
1922 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
1923 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
1924 {{0x0000,0x0000,0x0000}, 0x0000}};
1926 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1928 int cCount = cChars;
1929 WCHAR *input;
1930 IndicSyllable *syllables = NULL;
1931 int syllable_count = 0;
1932 BOOL modern = get_GSUB_Indic2(psa, psc);
1934 if (*pcGlyphs != cChars)
1936 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1937 return;
1940 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1941 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1943 /* Step 1: Compose Consonents */
1944 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
1945 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1947 /* Step 2: Reorder within Syllables */
1948 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
1949 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1950 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1951 *pcGlyphs = cCount;
1953 /* Step 3: Base Form application to syllables */
1954 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
1956 HeapFree(GetProcessHeap(),0,input);
1957 HeapFree(GetProcessHeap(),0,syllables);
1960 static int gujarati_lex(WCHAR c)
1962 switch (c)
1964 case 0x0AB0: return lex_Ra;
1965 default:
1966 return unicode_lex(c);
1970 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1972 int cCount = cChars;
1973 WCHAR *input;
1974 IndicSyllable *syllables = NULL;
1975 int syllable_count = 0;
1976 BOOL modern = get_GSUB_Indic2(psa, psc);
1978 if (*pcGlyphs != cChars)
1980 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1981 return;
1984 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1985 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1987 /* Step 1: Reorder within Syllables */
1988 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
1989 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1990 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1991 *pcGlyphs = cCount;
1993 /* Step 2: Base Form application to syllables */
1994 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
1996 HeapFree(GetProcessHeap(),0,input);
1997 HeapFree(GetProcessHeap(),0,syllables);
2000 static int oriya_lex(WCHAR c)
2002 switch (c)
2004 case 0x0B30: return lex_Ra;
2005 default:
2006 return unicode_lex(c);
2010 static const VowelComponents Oriya_vowels[] = {
2011 {0x0B48, {0x0B47,0x0B56,0x0000}},
2012 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2013 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2014 {0x0000, {0x0000,0x0000,0x0000}}};
2016 static const ConsonantComponents Oriya_consonants[] = {
2017 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2018 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2019 {{0x0000,0x0000,0x0000}, 0x0000}};
2021 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2023 int cCount = cChars;
2024 WCHAR *input;
2025 IndicSyllable *syllables = NULL;
2026 int syllable_count = 0;
2027 BOOL modern = get_GSUB_Indic2(psa, psc);
2029 if (*pcGlyphs != cChars)
2031 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2032 return;
2035 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2036 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2038 /* Step 1: Decompose Vowels and Compose Consonents */
2039 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2040 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2041 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2043 /* Step 2: Reorder within Syllables */
2044 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2045 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2046 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2047 *pcGlyphs = cCount;
2049 /* Step 3: Base Form application to syllables */
2050 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2052 HeapFree(GetProcessHeap(),0,input);
2053 HeapFree(GetProcessHeap(),0,syllables);
2056 static int tamil_lex(WCHAR c)
2058 return unicode_lex(c);
2061 static const VowelComponents Tamil_vowels[] = {
2062 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2063 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2064 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2065 {0x0000, {0x0000,0x0000,0x0000}}};
2067 static const ConsonantComponents Tamil_consonants[] = {
2068 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2069 {{0x0000,0x0000,0x0000}, 0x0000}};
2071 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2073 int cCount = cChars;
2074 WCHAR *input;
2075 IndicSyllable *syllables = NULL;
2076 int syllable_count = 0;
2077 BOOL modern = get_GSUB_Indic2(psa, psc);
2079 if (*pcGlyphs != cChars)
2081 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2082 return;
2085 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2086 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2088 /* Step 1: Decompose Vowels and Compose Consonents */
2089 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2090 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2091 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2093 /* Step 2: Reorder within Syllables */
2094 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2095 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2096 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2097 *pcGlyphs = cCount;
2099 /* Step 3: Base Form application to syllables */
2100 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2102 HeapFree(GetProcessHeap(),0,input);
2103 HeapFree(GetProcessHeap(),0,syllables);
2106 static int telugu_lex(WCHAR c)
2108 switch (c)
2110 case 0x0C43:
2111 case 0x0C44: return lex_Modifier;
2112 default:
2113 return unicode_lex(c);
2117 static const VowelComponents Telugu_vowels[] = {
2118 {0x0C48, {0x0C46,0x0C56,0x0000}},
2119 {0x0000, {0x0000,0x0000,0x0000}}};
2121 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2123 int cCount = cChars;
2124 WCHAR *input;
2125 IndicSyllable *syllables = NULL;
2126 int syllable_count = 0;
2127 BOOL modern = get_GSUB_Indic2(psa, psc);
2129 if (*pcGlyphs != cChars)
2131 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2132 return;
2135 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2136 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2138 /* Step 1: Decompose Vowels */
2139 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2140 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2142 /* Step 2: Reorder within Syllables */
2143 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2144 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2145 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2146 *pcGlyphs = cCount;
2148 /* Step 3: Base Form application to syllables */
2149 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2151 HeapFree(GetProcessHeap(),0,input);
2152 HeapFree(GetProcessHeap(),0,syllables);
2155 static int kannada_lex(WCHAR c)
2157 switch (c)
2159 case 0x0CB0: return lex_Ra;
2160 default:
2161 return unicode_lex(c);
2165 static const VowelComponents Kannada_vowels[] = {
2166 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2167 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2168 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2169 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2170 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2171 {0x0000, {0x0000,0x0000,0x0000}}};
2173 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2175 int cCount = cChars;
2176 WCHAR *input;
2177 IndicSyllable *syllables = NULL;
2178 int syllable_count = 0;
2179 BOOL modern = get_GSUB_Indic2(psa, psc);
2181 if (*pcGlyphs != cChars)
2183 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2184 return;
2187 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2188 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2190 /* Step 1: Decompose Vowels */
2191 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2192 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2194 /* Step 2: Reorder within Syllables */
2195 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2196 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2197 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2198 *pcGlyphs = cCount;
2200 /* Step 3: Base Form application to syllables */
2201 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2203 HeapFree(GetProcessHeap(),0,input);
2204 HeapFree(GetProcessHeap(),0,syllables);
2207 static int malayalam_lex(WCHAR c)
2209 return unicode_lex(c);
2212 static const VowelComponents Malayalam_vowels[] = {
2213 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2214 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2215 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2216 {0x0000, {0x0000,0x0000,0x0000}}};
2218 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2220 int cCount = cChars;
2221 WCHAR *input;
2222 IndicSyllable *syllables = NULL;
2223 int syllable_count = 0;
2224 BOOL modern = get_GSUB_Indic2(psa, psc);
2226 if (*pcGlyphs != cChars)
2228 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2229 return;
2232 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2233 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2235 /* Step 1: Decompose Vowels */
2236 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2237 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2239 /* Step 2: Reorder within Syllables */
2240 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2241 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2242 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2243 *pcGlyphs = cCount;
2245 /* Step 3: Base Form application to syllables */
2246 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2248 HeapFree(GetProcessHeap(),0,input);
2249 HeapFree(GetProcessHeap(),0,syllables);
2252 static int khmer_lex(WCHAR c)
2254 return unicode_lex(c);
2257 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2259 int cCount = cChars;
2260 WCHAR *input;
2261 IndicSyllable *syllables = NULL;
2262 int syllable_count = 0;
2264 if (*pcGlyphs != cChars)
2266 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2267 return;
2270 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2271 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2273 /* Step 1: Reorder within Syllables */
2274 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2275 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2276 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2277 *pcGlyphs = cCount;
2279 /* Step 2: Base Form application to syllables */
2280 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2282 HeapFree(GetProcessHeap(),0,input);
2283 HeapFree(GetProcessHeap(),0,syllables);
2286 static inline BOOL mongolian_wordbreak(WCHAR chr)
2288 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2291 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2293 INT *context_shape;
2294 INT dirL;
2295 int i;
2297 if (*pcGlyphs != cChars)
2299 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2300 return;
2303 if (!psa->fLogicalOrder && psa->fRTL)
2304 dirL = -1;
2305 else
2306 dirL = 1;
2308 if (!psc->GSUB_Table)
2309 psc->GSUB_Table = load_gsub_table(hdc);
2311 if (!psc->GSUB_Table)
2312 return;
2314 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2316 for (i = 0; i < cChars; i++)
2318 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2320 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2321 context_shape[i] = Xn;
2322 else
2323 context_shape[i] = Xl;
2325 else
2327 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2328 context_shape[i] = Xr;
2329 else
2330 context_shape[i] = Xm;
2334 /* Contextual Shaping */
2335 i = 0;
2336 while(i < *pcGlyphs)
2338 INT nextIndex;
2339 INT prevCount = *pcGlyphs;
2340 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2341 if (nextIndex > GSUB_E_NOGLYPH)
2343 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2344 i = nextIndex;
2346 else
2347 i++;
2350 HeapFree(GetProcessHeap(),0,context_shape);
2353 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)
2355 int i,k;
2357 for (i = 0; i < cGlyphs; i++)
2359 int char_index[20];
2360 int char_count = 0;
2362 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2363 if (k>=0)
2365 for (; k < cChars && pwLogClust[k] == i; k++)
2366 char_index[char_count++] = k;
2369 if (char_count == 0)
2370 continue;
2372 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2374 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2375 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2377 else
2378 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2381 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2382 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2385 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 )
2387 int i,k;
2388 int initGlyph, finaGlyph;
2389 INT dirR, dirL;
2390 BYTE *spaces;
2392 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2393 memset(spaces,0,cGlyphs);
2395 if (!psa->fLogicalOrder && psa->fRTL)
2397 initGlyph = cGlyphs-1;
2398 finaGlyph = 0;
2399 dirR = 1;
2400 dirL = -1;
2402 else
2404 initGlyph = 0;
2405 finaGlyph = cGlyphs-1;
2406 dirR = -1;
2407 dirL = 1;
2410 for (i = 0; i < cGlyphs; i++)
2412 for (k = 0; k < cChars; k++)
2413 if (pwLogClust[k] == i)
2415 if (pwcChars[k] == 0x0020)
2416 spaces[i] = 1;
2420 for (i = 0; i < cGlyphs; i++)
2422 int char_index[20];
2423 int char_count = 0;
2424 BOOL isInit, isFinal;
2426 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2427 if (k>=0)
2429 for (; k < cChars && pwLogClust[k] == i; k++)
2430 char_index[char_count++] = k;
2433 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2434 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2436 if (char_count == 0)
2437 continue;
2439 if (char_count == 1)
2441 if (pwcChars[char_index[0]] == 0x0020) /* space */
2443 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2444 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2446 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2447 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2448 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2450 if (!isInit && !isFinal)
2451 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2452 else if (isInit)
2453 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2454 else
2455 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2457 else if (!isInit)
2459 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2460 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2461 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2462 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2463 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2464 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2465 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2466 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2467 else
2468 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2470 else if (!isInit && !isFinal)
2471 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2472 else
2473 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2475 else if (char_count == 2)
2477 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2478 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2479 else if (!isInit)
2480 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2481 else
2482 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2484 else if (!isInit && !isFinal)
2485 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2486 else
2487 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2490 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2491 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2492 HeapFree(GetProcessHeap(),0,spaces);
2495 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 )
2497 int i,k;
2498 int finaGlyph;
2499 INT dirL;
2500 BYTE *spaces;
2502 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2503 memset(spaces,0,cGlyphs);
2505 if (!psa->fLogicalOrder && psa->fRTL)
2507 finaGlyph = 0;
2508 dirL = -1;
2510 else
2512 finaGlyph = cGlyphs-1;
2513 dirL = 1;
2516 for (i = 0; i < cGlyphs; i++)
2518 for (k = 0; k < cChars; k++)
2519 if (pwLogClust[k] == i)
2521 if (pwcChars[k] == 0x0020)
2522 spaces[i] = 1;
2526 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2528 for (i = 0; i < cGlyphs; i++)
2530 int char_index[20];
2531 int char_count = 0;
2533 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2534 if (k>=0)
2536 for (; k < cChars && pwLogClust[k] == i; k++)
2537 char_index[char_count++] = k;
2540 if (char_count == 0)
2541 continue;
2543 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2545 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2546 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2548 else if (i == finaGlyph)
2549 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2550 else
2551 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2553 /* handle Thai SARA AM (U+0E33) differently than GDEF */
2554 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
2555 pGlyphProp[i].sva.fClusterStart = 0;
2558 HeapFree(GetProcessHeap(),0,spaces);
2559 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2561 /* Do not allow justification between marks and their base */
2562 for (i = 0; i < cGlyphs; i++)
2564 if (!pGlyphProp[i].sva.fClusterStart)
2565 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2569 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)
2571 int i,k;
2573 for (i = 0; i < cGlyphs; i++)
2575 int char_index[20];
2576 int char_count = 0;
2578 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2579 if (k>=0)
2581 for (; k < cChars && pwLogClust[k] == i; k++)
2582 char_index[char_count++] = k;
2585 if (char_count == 0)
2586 continue;
2588 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2590 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2591 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2593 else
2594 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2596 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2597 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2600 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)
2602 int i,k;
2604 for (i = 0; i < cGlyphs; i++)
2606 int char_index[20];
2607 int char_count = 0;
2609 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2610 if (k>=0)
2612 for (; k < cChars && pwLogClust[k] == i; k++)
2613 char_index[char_count++] = k;
2616 if (char_count == 0)
2617 continue;
2619 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2621 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2622 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2624 else
2625 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2627 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2628 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2630 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2631 for (i = 0; i < cGlyphs; i++)
2633 if (!pGlyphProp[i].sva.fClusterStart)
2635 pGlyphProp[i].sva.fDiacritic = 0;
2636 pGlyphProp[i].sva.fZeroWidth = 0;
2641 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)
2643 int i,k;
2645 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2646 for (i = 0; i < cGlyphs; i++)
2648 int char_index[20];
2649 int char_count = 0;
2651 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2652 if (k>=0)
2654 for (; k < cChars && pwLogClust[k] == i; k++)
2655 char_index[char_count++] = k;
2658 if (override_gsub)
2660 /* Most indic scripts do not set fDiacritic or fZeroWidth */
2661 pGlyphProp[i].sva.fDiacritic = FALSE;
2662 pGlyphProp[i].sva.fZeroWidth = FALSE;
2665 if (char_count == 0)
2666 continue;
2668 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2670 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2671 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2673 else
2674 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2676 pGlyphProp[i].sva.fClusterStart = 0;
2677 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2678 switch (lexical(pwcChars[char_index[k]]))
2680 case lex_Matra_pre:
2681 case lex_Matra_post:
2682 case lex_Matra_above:
2683 case lex_Matra_below:
2684 case lex_Modifier:
2685 case lex_Halant:
2686 break;
2687 case lex_ZWJ:
2688 case lex_ZWNJ:
2689 /* check for dangling joiners */
2690 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
2691 pGlyphProp[i].sva.fClusterStart = 1;
2692 else
2693 k = char_count;
2694 break;
2695 default:
2696 pGlyphProp[i].sva.fClusterStart = 1;
2697 break;
2701 if (use_syllables)
2703 IndicSyllable *syllables = NULL;
2704 int syllable_count = 0;
2705 BOOL modern = get_GSUB_Indic2(psa, psc);
2707 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
2709 for (i = 0; i < syllable_count; i++)
2711 int j;
2712 WORD g = pwLogClust[syllables[i].start];
2713 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
2715 if (pwLogClust[j] != g)
2717 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
2718 pwLogClust[j] = g;
2723 HeapFree(GetProcessHeap(), 0, syllables);
2726 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2729 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 )
2731 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
2734 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 )
2736 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
2739 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 )
2741 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
2744 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 )
2746 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
2749 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 )
2751 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
2754 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 )
2756 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
2759 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 )
2761 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
2764 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 )
2766 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
2769 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 )
2771 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
2774 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 )
2776 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
2779 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 )
2781 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
2784 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)
2786 if (ShapingData[psa->eScript].charGlyphPropProc)
2787 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2788 else
2789 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2792 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2794 if (!psc->GSUB_Table)
2795 psc->GSUB_Table = load_gsub_table(hdc);
2797 if (ShapingData[psa->eScript].contextProc)
2798 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2801 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)
2803 int i;
2804 INT dirL;
2806 if (!rpRangeProperties)
2807 return;
2809 if (!psc->GSUB_Table)
2810 psc->GSUB_Table = load_gsub_table(hdc);
2812 if (!psc->GSUB_Table)
2813 return;
2815 if (!psa->fLogicalOrder && psa->fRTL)
2816 dirL = -1;
2817 else
2818 dirL = 1;
2820 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
2822 if (rpRangeProperties->potfRecords[i].lParameter > 0)
2823 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
2827 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
2829 const TEXTRANGE_PROPERTIES *rpRangeProperties;
2830 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
2832 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
2835 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
2837 LoadedFeature *feature;
2838 int i;
2840 if (!ShapingData[psa->eScript].requiredFeatures)
2841 return S_OK;
2843 if (!psc->GSUB_Table)
2844 psc->GSUB_Table = load_gsub_table(hdc);
2846 /* we need to have at least one of the required features */
2847 i = 0;
2848 while (ShapingData[psa->eScript].requiredFeatures[i])
2850 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
2851 if (feature)
2852 return S_OK;
2853 i++;
2856 return USP_E_SCRIPT_NOT_IN_FONT;
2859 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
2860 SCRIPT_ANALYSIS *psa, int cMaxTags,
2861 OPENTYPE_TAG *pScriptTags, int *pcTags)
2863 HRESULT hr;
2864 OPENTYPE_TAG searching = 0x00000000;
2866 if (!psc->GSUB_Table)
2867 psc->GSUB_Table = load_gsub_table(hdc);
2869 if (psa && scriptInformation[psa->eScript].scriptTag)
2870 searching = scriptInformation[psa->eScript].scriptTag;
2872 hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL);
2873 if (FAILED(hr))
2874 *pcTags = 0;
2875 return hr;
2878 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
2879 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2880 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
2881 int *pcTags)
2883 HRESULT hr;
2884 OPENTYPE_TAG searching = 0x00000000;
2885 BOOL fellback = FALSE;
2887 if (!psc->GSUB_Table)
2888 psc->GSUB_Table = load_gsub_table(hdc);
2890 if (psa && psc->userLang != 0)
2891 searching = psc->userLang;
2893 hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL);
2894 if (FAILED(hr))
2896 fellback = TRUE;
2897 hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL);
2900 if (FAILED(hr) || fellback)
2901 *pcTags = 0;
2902 if (SUCCEEDED(hr) && fellback && psa)
2903 hr = E_INVALIDARG;
2904 return hr;
2907 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
2908 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2909 OPENTYPE_TAG tagLangSys, int cMaxTags,
2910 OPENTYPE_TAG *pFeatureTags, int *pcTags)
2912 HRESULT hr;
2913 BOOL filter = FALSE;
2915 if (!psc->GSUB_Table)
2916 psc->GSUB_Table = load_gsub_table(hdc);
2918 if (psa && scriptInformation[psa->eScript].scriptTag)
2920 FIXME("Filtering not implemented\n");
2921 filter = TRUE;
2924 hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL);
2926 if (FAILED(hr))
2927 *pcTags = 0;
2928 return hr;