usp10: Insert dotted circle (U+25CC) for invalid combining sequences in Arabic.
[wine/multimedia.git] / dlls / usp10 / shape.c
blob84953fb795291e4dc9f6980bc92cea3483ac80ef
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 typedef int (*combining_lexical_function)(WCHAR c);
119 /* the orders of joined_forms and contextual_features need to line up */
120 static const char* contextual_features[] =
122 "isol",
123 "fina",
124 "init",
125 "medi",
126 /* Syriac Alaph */
127 "med2",
128 "fin2",
129 "fin3"
132 static OPENTYPE_FEATURE_RECORD standard_features[] =
134 { MS_MAKE_TAG('c','c','m','p'), 1},
135 { MS_MAKE_TAG('l','o','c','l'), 1},
138 static OPENTYPE_FEATURE_RECORD latin_features[] =
140 { MS_MAKE_TAG('l','i','g','a'), 1},
141 { MS_MAKE_TAG('c','l','i','g'), 1},
144 static OPENTYPE_FEATURE_RECORD arabic_features[] =
146 { MS_MAKE_TAG('r','l','i','g'), 1},
147 { MS_MAKE_TAG('c','a','l','t'), 1},
148 { MS_MAKE_TAG('l','i','g','a'), 1},
149 { MS_MAKE_TAG('d','l','i','g'), 1},
150 { MS_MAKE_TAG('c','s','w','h'), 1},
151 { MS_MAKE_TAG('m','s','e','t'), 1},
154 static const char* required_arabic_features[] =
156 "fina",
157 "init",
158 "medi",
159 "rlig",
160 NULL
163 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
165 { MS_MAKE_TAG('d','l','i','g'), 0},
168 static OPENTYPE_FEATURE_RECORD syriac_features[] =
170 { MS_MAKE_TAG('r','l','i','g'), 1},
171 { MS_MAKE_TAG('c','a','l','t'), 1},
172 { MS_MAKE_TAG('l','i','g','a'), 1},
173 { MS_MAKE_TAG('d','l','i','g'), 1},
176 static const char* required_syriac_features[] =
178 "fina",
179 "fin2",
180 "fin3",
181 "init",
182 "medi",
183 "med2",
184 "rlig",
185 NULL
188 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
190 /* Presentation forms */
191 { MS_MAKE_TAG('b','l','w','s'), 1},
192 { MS_MAKE_TAG('a','b','v','s'), 1},
193 { MS_MAKE_TAG('p','s','t','s'), 1},
196 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
198 { MS_MAKE_TAG('a','b','v','s'), 1},
199 { MS_MAKE_TAG('b','l','w','s'), 1},
202 static OPENTYPE_FEATURE_RECORD phags_features[] =
204 { MS_MAKE_TAG('a','b','v','s'), 1},
205 { MS_MAKE_TAG('b','l','w','s'), 1},
206 { MS_MAKE_TAG('c','a','l','t'), 1},
209 static OPENTYPE_FEATURE_RECORD thai_features[] =
211 { MS_MAKE_TAG('c','c','m','p'), 1},
214 static const char* required_lao_features[] =
216 "ccmp",
217 NULL
220 static const char* required_devanagari_features[] =
222 "nukt",
223 "akhn",
224 "rphf",
225 "blwf",
226 "half",
227 "vatu",
228 "pres",
229 "abvs",
230 "blws",
231 "psts",
232 "haln",
233 NULL
236 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
238 { MS_MAKE_TAG('p','r','e','s'), 1},
239 { MS_MAKE_TAG('a','b','v','s'), 1},
240 { MS_MAKE_TAG('b','l','w','s'), 1},
241 { MS_MAKE_TAG('p','s','t','s'), 1},
242 { MS_MAKE_TAG('h','a','l','n'), 1},
243 { MS_MAKE_TAG('c','a','l','t'), 1},
246 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
248 { MS_MAKE_TAG('l','i','g','a'), 1},
249 { MS_MAKE_TAG('c','l','i','g'), 1},
252 static const char* required_bengali_features[] =
254 "nukt",
255 "akhn",
256 "rphf",
257 "blwf",
258 "half",
259 "vatu",
260 "pstf",
261 "init",
262 "abvs",
263 "blws",
264 "psts",
265 "haln",
266 NULL
269 static const char* required_gurmukhi_features[] =
271 "nukt",
272 "akhn",
273 "rphf",
274 "blwf",
275 "half",
276 "pstf",
277 "vatu",
278 "cjct",
279 "pres",
280 "abvs",
281 "blws",
282 "psts",
283 "haln",
284 "calt",
285 NULL
288 static const char* required_oriya_features[] =
290 "nukt",
291 "akhn",
292 "rphf",
293 "blwf",
294 "pstf",
295 "cjct",
296 "pres",
297 "abvs",
298 "blws",
299 "psts",
300 "haln",
301 "calt",
302 NULL
305 static const char* required_tamil_features[] =
307 "nukt",
308 "akhn",
309 "rphf",
310 "pref",
311 "half",
312 "pres",
313 "abvs",
314 "blws",
315 "psts",
316 "haln",
317 "calt",
318 NULL
321 static const char* required_telugu_features[] =
323 "nukt",
324 "akhn",
325 "rphf",
326 "pref",
327 "half",
328 "pstf",
329 "cjct",
330 "pres",
331 "abvs",
332 "blws",
333 "psts",
334 "haln",
335 "calt",
336 NULL
339 static OPENTYPE_FEATURE_RECORD khmer_features[] =
341 { MS_MAKE_TAG('p','r','e','s'), 1},
342 { MS_MAKE_TAG('b','l','w','s'), 1},
343 { MS_MAKE_TAG('a','b','v','s'), 1},
344 { MS_MAKE_TAG('p','s','t','s'), 1},
345 { MS_MAKE_TAG('c','l','i','g'), 1},
348 static const char* required_khmer_features[] =
350 "pref",
351 "blwf",
352 "abvf",
353 "pstf",
354 "pres",
355 "blws",
356 "abvs",
357 "psts",
358 "clig",
359 NULL
362 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
364 { MS_MAKE_TAG('c','c','m','p'), 1},
365 { MS_MAKE_TAG('l','o','c','l'), 1},
366 { MS_MAKE_TAG('c','a','l','t'), 1},
367 { MS_MAKE_TAG('l','i','g','a'), 1},
370 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
372 { MS_MAKE_TAG('c','c','m','p'), 1},
373 { MS_MAKE_TAG('l','o','c','l'), 1},
374 { MS_MAKE_TAG('c','a','l','t'), 1},
375 { MS_MAKE_TAG('r','l','i','g'), 1},
378 typedef struct ScriptShapeDataTag {
379 TEXTRANGE_PROPERTIES defaultTextRange;
380 const char** requiredFeatures;
381 OPENTYPE_TAG newOtTag;
382 ContextualShapingProc contextProc;
383 ShapeCharGlyphPropProc charGlyphPropProc;
384 } ScriptShapeData;
386 /* in order of scripts */
387 static const ScriptShapeData ShapingData[] =
389 {{ standard_features, 2}, NULL, 0, NULL, NULL},
390 {{ latin_features, 2}, NULL, 0, NULL, NULL},
391 {{ latin_features, 2}, NULL, 0, NULL, NULL},
392 {{ latin_features, 2}, NULL, 0, NULL, NULL},
393 {{ standard_features, 2}, NULL, 0, NULL, NULL},
394 {{ latin_features, 2}, NULL, 0, NULL, NULL},
395 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
396 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
397 {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
398 {{ syriac_features, 4}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
399 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
400 {{ NULL, 0}, NULL, 0, NULL, ShapeCharGlyphProp_None},
401 {{ standard_features, 2}, NULL, 0, NULL, NULL},
402 {{ standard_features, 2}, NULL, 0, NULL, NULL},
403 {{ standard_features, 2}, NULL, 0, NULL, NULL},
404 {{ standard_features, 2}, NULL, 0, NULL, NULL},
405 {{ sinhala_features, 3}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
406 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
407 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
408 {{ phags_features, 3}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
409 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
410 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
411 {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
412 {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
413 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
414 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
415 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
416 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
417 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
418 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
419 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
420 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
421 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
422 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
423 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
424 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
425 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
426 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
427 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
428 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
429 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
430 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
431 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
432 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
433 {{ standard_features, 2}, NULL, 0, NULL, NULL},
434 {{ latin_features, 2}, NULL, 0, NULL, NULL},
435 {{ standard_features, 2}, NULL, 0, NULL, NULL},
436 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
437 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
438 {{ standard_features, 2}, NULL, 0, NULL, NULL},
439 {{ standard_features, 2}, NULL, 0, NULL, NULL},
440 {{ standard_features, 2}, NULL, 0, NULL, NULL},
441 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
442 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
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 {{ NULL, 0}, NULL, 0, NULL, NULL},
448 {{ NULL, 0}, NULL, 0, NULL, NULL},
449 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
450 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
451 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
452 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, 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 {{ NULL, 0}, NULL, 0, NULL, NULL},
467 {{ NULL, 0}, NULL, 0, NULL, NULL},
468 {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
469 {{ latin_features, 2}, NULL, 0, NULL, NULL},
470 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
473 extern scriptData scriptInformation[];
475 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
477 int i;
478 int out_index = GSUB_E_NOGLYPH;
480 TRACE("%i lookups\n", feature->lookup_count);
481 for (i = 0; i < feature->lookup_count; i++)
483 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
484 if (out_index != GSUB_E_NOGLYPH)
485 break;
487 if (out_index == GSUB_E_NOGLYPH)
488 TRACE("lookups found no glyphs\n");
489 else
491 int out2;
492 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
493 if (out2!=GSUB_E_NOGLYPH)
494 out_index = out2;
496 return out_index;
499 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
501 UINT charset;
503 if (psc->userScript != 0)
505 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
506 return ShapingData[psa->eScript].newOtTag;
507 else
508 return psc->userScript;
511 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
512 return ShapingData[psa->eScript].newOtTag;
514 if (scriptInformation[psa->eScript].scriptTag)
515 return scriptInformation[psa->eScript].scriptTag;
518 * fall back to the font charset
520 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
521 switch (charset)
523 case ANSI_CHARSET:
524 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
525 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
526 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
527 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
528 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
529 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
530 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
531 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
532 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
533 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
534 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
535 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
536 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
537 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
538 default: return MS_MAKE_TAG('l','a','t','n');
542 static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
544 LoadedFeature *feature = NULL;
546 if (psc->GSUB_Table)
548 int attempt = 2;
549 OPENTYPE_TAG tags;
550 OPENTYPE_TAG language;
551 OPENTYPE_TAG script;
552 int cTags;
556 script = get_opentype_script(hdc,psa,psc,(attempt==2));
557 if (psc->userLang != 0)
558 language = psc->userLang;
559 else
560 language = MS_MAKE_TAG('d','f','l','t');
561 attempt--;
563 OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
565 } while(attempt && !feature);
567 /* try in the default (latin) table */
568 if (!feature)
569 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);
572 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
573 return feature;
576 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)
578 LoadedFeature *feature;
580 feature = load_GSUB_feature(hdc, psa, psc, feat);
581 if (!feature)
582 return GSUB_E_NOFEATURE;
584 TRACE("applying feature %s\n",feat);
585 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
588 static VOID *load_gsub_table(HDC hdc)
590 VOID* GSUB_Table = NULL;
591 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
592 if (length != GDI_ERROR)
594 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
595 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
596 TRACE("Loaded GSUB table of %i bytes\n",length);
598 return GSUB_Table;
601 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)
603 WORD *glyphs;
604 INT glyph_count = count;
605 INT rc;
607 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
608 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
609 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
610 if (rc > GSUB_E_NOGLYPH)
611 rc = count - glyph_count;
612 else
613 rc = 0;
615 HeapFree(GetProcessHeap(),0,glyphs);
616 return rc;
619 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
621 int i;
623 for (i = 0; i < cGlyphs; i++)
625 if (!pGlyphProp[i].sva.fClusterStart)
627 int j;
628 for (j = 0; j < cChars; j++)
630 if (pwLogClust[j] == i)
632 int k = j;
633 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
634 k-=1;
635 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
636 pwLogClust[j] = pwLogClust[k];
643 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
645 if (changeCount == 0)
646 return;
647 else
649 int i;
650 int target_glyph = nextIndex - write_dir;
651 int seeking_glyph;
652 int target_index = -1;
653 int replacing_glyph = -1;
654 int changed = 0;
655 int top_logclust = 0;
657 if (changeCount > 0)
659 if (write_dir > 0)
660 target_glyph = nextIndex - changeCount;
661 else
662 target_glyph = nextIndex + (changeCount + 1);
665 seeking_glyph = target_glyph;
666 for (i = 0; i < chars; i++)
667 if (pwLogClust[i] > top_logclust)
668 top_logclust = pwLogClust[i];
670 do {
671 if (write_dir > 0)
672 for (i = 0; i < chars; i++)
674 if (pwLogClust[i] == seeking_glyph)
676 target_index = i;
677 break;
680 else
681 for (i = chars - 1; i >= 0; i--)
683 if (pwLogClust[i] == seeking_glyph)
685 target_index = i;
686 break;
689 if (target_index == -1)
690 seeking_glyph ++;
692 while (target_index == -1 && seeking_glyph <= top_logclust);
694 if (target_index == -1)
696 ERR("Unable to find target glyph\n");
697 return;
700 if (changeCount < 0)
702 /* merge glyphs */
703 for(i = target_index; i < chars && i >= 0; i+=write_dir)
705 if (pwLogClust[i] == target_glyph)
706 continue;
707 if(pwLogClust[i] == replacing_glyph)
708 pwLogClust[i] = target_glyph;
709 else
711 changed--;
712 if (changed >= changeCount)
714 replacing_glyph = pwLogClust[i];
715 pwLogClust[i] = target_glyph;
717 else
718 break;
722 /* renumber trailing indexes*/
723 for(i = target_index; i < chars && i >= 0; i+=write_dir)
725 if (pwLogClust[i] != target_glyph)
726 pwLogClust[i] += changeCount;
729 else
731 for(i = target_index; i < chars && i >= 0; i+=write_dir)
732 pwLogClust[i] += changeCount;
737 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 )
739 if (psc->GSUB_Table)
741 LoadedFeature *feature;
742 int lookup_index;
744 feature = load_GSUB_feature(hdc, psa, psc, feat);
745 if (!feature)
746 return GSUB_E_NOFEATURE;
748 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
749 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
751 int i;
753 if (write_dir > 0)
754 i = 0;
755 else
756 i = *pcGlyphs-1;
757 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
758 while(i < *pcGlyphs && i >= 0)
760 INT nextIndex;
761 INT prevCount = *pcGlyphs;
763 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
764 if (*pcGlyphs != prevCount)
766 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
767 i = nextIndex;
769 else
770 i+=write_dir;
773 return *pcGlyphs;
775 return GSUB_E_NOFEATURE;
778 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
780 OPENTYPE_TAG tag;
781 HRESULT hr;
782 int count = 0;
784 hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL);
786 return(SUCCEEDED(hr));
789 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
791 int i;
792 for (i = *pcGlyphs; i>=index; i--)
793 pwGlyphs[i+1] = pwGlyphs[i];
794 pwGlyphs[index] = glyph;
795 *pcGlyphs = *pcGlyphs+1;
796 if (write_dir < 0)
797 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
798 else
799 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
802 static void mark_invalid_combinations(HDC hdc, const WCHAR* pwcChars, INT cChars, WORD *pwGlyphs, INT *pcGlyphs, INT write_dir, WORD *pwLogClust, combining_lexical_function lex)
804 CHAR *context_type;
805 int i,g;
806 WCHAR invalid = 0x25cc;
807 WORD invalid_glyph;
809 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
811 /* Mark invalid combinations */
812 for (i = 0; i < cChars; i++)
813 context_type[i] = lex(pwcChars[i]);
815 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
816 for (i = 1, g=1; i < cChars; i++, g++)
818 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
820 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
821 g++;
825 HeapFree(GetProcessHeap(),0,context_type);
828 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
830 if (i + delta < 0)
831 return 0;
832 if ( i+ delta >= cchLen)
833 return 0;
835 i += delta;
837 return chars[i];
840 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
842 if (i + delta < 0)
844 if (psa->fLinkBefore)
845 return jtR;
846 else
847 return jtU;
849 if ( i+ delta >= cchLen)
851 if (psa->fLinkAfter)
852 return jtL;
853 else
854 return jtU;
857 i += delta;
859 if (context_type[i] == jtT)
860 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
861 else
862 return context_type[i];
865 static inline BOOL right_join_causing(CHAR joining_type)
867 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
870 static inline BOOL left_join_causing(CHAR joining_type)
872 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
875 static inline BOOL word_break_causing(WCHAR chr)
877 /* we are working within a string of characters already guareented to
878 be within one script, Syriac, so we do not worry about any character
879 other than the space character outside of that range */
880 return (chr == 0 || chr == 0x20 );
883 static int combining_lexical_Arabic(WCHAR c)
885 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
887 switch(c)
889 case 0x064B:
890 case 0x064C:
891 case 0x064E:
892 case 0x064F:
893 case 0x0652:
894 case 0x0657:
895 case 0x0658:
896 case 0x06E1: return Arab_DIAC1; break;
897 case 0x064D:
898 case 0x0650:
899 case 0x0656: return Arab_DIAC2; break;
900 case 0x0651: return Arab_DIAC3; break;
901 case 0x0610:
902 case 0x0611:
903 case 0x0612:
904 case 0x0613:
905 case 0x0614:
906 case 0x0659:
907 case 0x06D6:
908 case 0x06DC:
909 case 0x06DF:
910 case 0x06E0:
911 case 0x06E2:
912 case 0x06E4:
913 case 0x06E7:
914 case 0x06E8:
915 case 0x06EB:
916 case 0x06EC: return Arab_DIAC4; break;
917 case 0x06E3:
918 case 0x06EA:
919 case 0x06ED: return Arab_DIAC5; break;
920 case 0x0670: return Arab_DIAC6; break;
921 case 0x0653: return Arab_DIAC7; break;
922 case 0x0655:
923 case 0x0654: return Arab_DIAC8; break;
924 default: return Arab_Norm;
929 * ContextualShape_Arabic
931 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
933 CHAR *context_type;
934 INT *context_shape;
935 INT dirR, dirL;
936 int i;
938 if (*pcGlyphs != cChars)
940 ERR("Number of Glyphs and Chars need to match at the beginning\n");
941 return;
944 if (!psa->fLogicalOrder && psa->fRTL)
946 dirR = 1;
947 dirL = -1;
949 else
951 dirR = -1;
952 dirL = 1;
955 if (!psc->GSUB_Table)
956 psc->GSUB_Table = load_gsub_table(hdc);
958 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
959 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
961 for (i = 0; i < cChars; i++)
962 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
964 for (i = 0; i < cChars; i++)
966 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
967 context_shape[i] = Xr;
968 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
969 context_shape[i] = Xl;
970 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)))
971 context_shape[i] = Xm;
972 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
973 context_shape[i] = Xr;
974 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
975 context_shape[i] = Xl;
976 else
977 context_shape[i] = Xn;
980 /* Contextual Shaping */
981 i = 0;
982 while(i < *pcGlyphs)
984 BOOL shaped = FALSE;
986 if (psc->GSUB_Table)
988 INT nextIndex;
989 INT prevCount = *pcGlyphs;
990 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
991 if (nextIndex > GSUB_E_NOGLYPH)
993 i = nextIndex;
994 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
996 shaped = (nextIndex > GSUB_E_NOGLYPH);
999 if (!shaped)
1001 if (context_shape[i] == Xn)
1003 WORD newGlyph = pwOutGlyphs[i];
1004 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1006 /* fall back to presentation form B */
1007 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1008 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1009 pwOutGlyphs[i] = newGlyph;
1012 i++;
1016 HeapFree(GetProcessHeap(),0,context_shape);
1017 HeapFree(GetProcessHeap(),0,context_type);
1019 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1023 * ContextualShape_Syriac
1026 #define ALAPH 0x710
1027 #define DALATH 0x715
1028 #define RISH 0x72A
1030 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1032 CHAR *context_type;
1033 INT *context_shape;
1034 INT dirR, dirL;
1035 int i;
1037 if (*pcGlyphs != cChars)
1039 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1040 return;
1043 if (!psa->fLogicalOrder && psa->fRTL)
1045 dirR = 1;
1046 dirL = -1;
1048 else
1050 dirR = -1;
1051 dirL = 1;
1054 if (!psc->GSUB_Table)
1055 psc->GSUB_Table = load_gsub_table(hdc);
1057 if (!psc->GSUB_Table)
1058 return;
1060 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1061 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1063 for (i = 0; i < cChars; i++)
1064 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1066 for (i = 0; i < cChars; i++)
1068 if (pwcChars[i] == ALAPH)
1070 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1072 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1073 context_shape[i] = Afj;
1074 else if ( rchar != DALATH && rchar != RISH &&
1075 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1076 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1077 context_shape[i] = Afn;
1078 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1079 context_shape[i] = Afx;
1080 else
1081 context_shape[i] = Xn;
1083 else if (context_type[i] == jtR &&
1084 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1085 context_shape[i] = Xr;
1086 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1087 context_shape[i] = Xl;
1088 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)))
1089 context_shape[i] = Xm;
1090 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1091 context_shape[i] = Xr;
1092 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1093 context_shape[i] = Xl;
1094 else
1095 context_shape[i] = Xn;
1098 /* Contextual Shaping */
1099 i = 0;
1100 while(i < *pcGlyphs)
1102 INT nextIndex;
1103 INT prevCount = *pcGlyphs;
1104 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1105 if (nextIndex > GSUB_E_NOGLYPH)
1107 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1108 i = nextIndex;
1110 else
1111 i++;
1114 HeapFree(GetProcessHeap(),0,context_shape);
1115 HeapFree(GetProcessHeap(),0,context_type);
1119 * ContextualShape_Phags_pa
1122 #define phags_pa_CANDRABINDU 0xA873
1123 #define phags_pa_START 0xA840
1124 #define phags_pa_END 0xA87F
1126 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1128 INT *context_shape;
1129 INT dirR, dirL;
1130 int i;
1132 if (*pcGlyphs != cChars)
1134 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1135 return;
1138 if (!psa->fLogicalOrder && psa->fRTL)
1140 dirR = 1;
1141 dirL = -1;
1143 else
1145 dirR = -1;
1146 dirL = 1;
1149 if (!psc->GSUB_Table)
1150 psc->GSUB_Table = load_gsub_table(hdc);
1152 if (!psc->GSUB_Table)
1153 return;
1155 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1157 for (i = 0; i < cChars; i++)
1159 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1161 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1162 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1163 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1164 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1166 if (jrchar && jlchar)
1167 context_shape[i] = Xm;
1168 else if (jrchar)
1169 context_shape[i] = Xr;
1170 else if (jlchar)
1171 context_shape[i] = Xl;
1172 else
1173 context_shape[i] = Xn;
1175 else
1176 context_shape[i] = -1;
1179 /* Contextual Shaping */
1180 i = 0;
1181 while(i < *pcGlyphs)
1183 if (context_shape[i] >= 0)
1185 INT nextIndex;
1186 INT prevCount = *pcGlyphs;
1187 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1188 if (nextIndex > GSUB_E_NOGLYPH)
1190 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1191 i = nextIndex;
1193 else
1194 i++;
1196 else
1197 i++;
1200 HeapFree(GetProcessHeap(),0,context_shape);
1203 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1205 int i;
1207 /* Replace */
1208 pwOutChars[cWalk] = replacements[0];
1209 cWalk=cWalk+1;
1211 /* Insert */
1212 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1214 int j;
1215 for (j = *pcChars; j > cWalk; j--)
1216 pwOutChars[j] = pwOutChars[j-1];
1217 *pcChars= *pcChars+1;
1218 pwOutChars[cWalk] = replacements[i];
1219 cWalk = cWalk+1;
1223 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1225 int i;
1226 int cWalk;
1228 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1230 for (i = 0; vowels[i].base != 0x0; i++)
1232 if (pwOutChars[cWalk] == vowels[i].base)
1234 int o = 0;
1235 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1236 if (vowels[i].parts[1]) { cWalk++; o++; }
1237 if (vowels[i].parts[2]) { cWalk++; o++; }
1238 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1239 break;
1245 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1247 int i;
1248 int offset = 0;
1249 int cWalk;
1251 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1253 for (i = 0; consonants[i].output!= 0x0; i++)
1255 int j;
1256 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1257 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1258 break;
1260 if (consonants[i].parts[j]==0x0) /* matched all */
1262 int k;
1263 j--;
1264 pwOutChars[cWalk] = consonants[i].output;
1265 for(k = cWalk+1; k < *pcChars - j; k++)
1266 pwOutChars[k] = pwOutChars[k+j];
1267 *pcChars = *pcChars - j;
1268 for (k = j ; k > 0; k--)
1269 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1270 offset += j;
1271 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1272 pwLogClust[k]--;
1273 break;
1276 cWalk++;
1280 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1282 if (s->ralf >= 0)
1284 int j;
1285 WORD Ra = pwChar[s->start];
1286 WORD H = pwChar[s->start+1];
1288 TRACE("Doing reorder of Ra to %i\n",s->base);
1289 for (j = s->start; j < s->base-1; j++)
1290 pwChar[j] = pwChar[j+2];
1291 pwChar[s->base-1] = Ra;
1292 pwChar[s->base] = H;
1294 s->ralf = s->base-1;
1295 s->base -= 2;
1299 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1301 if (s->ralf >= 0)
1303 int j,loc;
1304 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1305 WORD Ra = pwChar[s->start];
1306 WORD H = pwChar[s->start+1];
1307 for (loc = s->end; loc > stop; loc--)
1308 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1309 break;
1311 TRACE("Doing reorder of Ra to %i\n",loc);
1312 for (j = s->start; j < loc-1; j++)
1313 pwChar[j] = pwChar[j+2];
1314 pwChar[loc-1] = Ra;
1315 pwChar[loc] = H;
1317 s->ralf = loc-1;
1318 s->base -= 2;
1319 if (s->blwf >= 0) s->blwf -= 2;
1320 if (s->pref >= 0) s->pref -= 2;
1324 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1326 if (s->ralf >= 0)
1328 int j;
1329 WORD Ra = pwChar[s->start];
1330 WORD H = pwChar[s->start+1];
1332 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1333 for (j = s->start; j < s->end-1; j++)
1334 pwChar[j] = pwChar[j+2];
1335 pwChar[s->end-1] = Ra;
1336 pwChar[s->end] = H;
1338 s->ralf = s->end-1;
1339 s->base -= 2;
1340 if (s->blwf >= 0) s->blwf -= 2;
1341 if (s->pref >= 0) s->pref -= 2;
1345 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1347 int i;
1349 /* reorder Matras */
1350 if (s->end > s->base)
1352 for (i = 1; i <= s->end-s->base; i++)
1354 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1356 int j;
1357 WCHAR c = pwChar[s->base+i];
1358 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1359 for (j = s->base+i; j > s->base; j--)
1360 pwChar[j] = pwChar[j-1];
1361 pwChar[s->base] = c;
1363 if (s->ralf >= s->base) s->ralf++;
1364 if (s->blwf >= s->base) s->blwf++;
1365 if (s->pref >= s->base) s->pref++;
1366 s->base ++;
1372 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1374 int i;
1376 /* reorder Matras */
1377 if (s->end > s->base)
1379 for (i = 1; i <= s->end-s->base; i++)
1381 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1383 int j;
1384 WCHAR c = pwChar[s->base+i];
1385 TRACE("Doing reorder of %x to %i\n",c,s->start);
1386 for (j = s->base+i; j > s->start; j--)
1387 pwChar[j] = pwChar[j-1];
1388 pwChar[s->start] = c;
1390 if (s->ralf >= 0) s->ralf++;
1391 if (s->blwf >= 0) s->blwf++;
1392 if (s->pref >= 0) s->pref++;
1393 s->base ++;
1399 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1401 if (s->blwf >= 0 && g->blwf > g->base)
1403 int j,loc;
1404 int g_offset;
1405 for (loc = s->end; loc > s->blwf; loc--)
1406 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1407 break;
1409 g_offset = (loc - s->blwf) - 1;
1411 if (loc != s->blwf)
1413 WORD blwf = glyphs[g->blwf];
1414 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1415 /* do not care about the pwChar array anymore, just the glyphs */
1416 for (j = 0; j < g_offset; j++)
1417 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1418 glyphs[g->blwf + g_offset] = blwf;
1423 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1425 int i;
1427 /* reorder previously moved Matras to correct position*/
1428 for (i = s->start; i < s->base; i++)
1430 if (lexical(pwChar[i]) == lex_Matra_pre)
1432 int j;
1433 int g_start = g->start + i - s->start;
1434 if (g_start < g->base -1 )
1436 WCHAR og = glyphs[g_start];
1437 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1438 for (j = g_start; j < g->base-1; j++)
1439 glyphs[j] = glyphs[j+1];
1440 glyphs[g->base-1] = og;
1446 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1448 if (s->pref >= 0 && g->pref > g->base)
1450 int j;
1451 WCHAR og = glyphs[g->pref];
1452 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1453 for (j = g->pref; j > g->base; j--)
1454 glyphs[j] = glyphs[j-1];
1455 glyphs[g->base] = og;
1459 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1461 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1462 if (s->start == s->base && s->base == s->end) return;
1463 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1465 Reorder_Ra_follows_base(pwChar, s, lexical);
1466 Reorder_Matra_precede_base(pwChar, s, lexical);
1469 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1471 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1472 if (s->start == s->base && s->base == s->end) return;
1473 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1475 Reorder_Ra_follows_matra(pwChar, s, lexical);
1476 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1479 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1481 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1482 if (s->start == s->base && s->base == s->end) return;
1483 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1485 Reorder_Ra_follows_base(pwChar, s, lexical);
1486 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1489 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1491 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1492 if (s->start == s->base && s->base == s->end) return;
1493 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1495 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1496 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1499 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1501 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1502 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1503 if (s->start == s->base && s->base == s->end) return;
1504 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1506 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1509 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1511 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1512 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1513 if (s->start == s->base && s->base == s->end) return;
1514 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1516 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1517 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1521 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1523 if (shift == 0)
1524 return;
1526 if (glyph_index->start > index)
1527 glyph_index->start += shift;
1528 if (glyph_index->base > index)
1529 glyph_index->base+= shift;
1530 if (glyph_index->end > index)
1531 glyph_index->end+= shift;
1532 if (glyph_index->ralf > index)
1533 glyph_index->ralf+= shift;
1534 if (glyph_index->blwf > index)
1535 glyph_index->blwf+= shift;
1536 if (glyph_index->pref > index)
1537 glyph_index->pref+= shift;
1540 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 )
1542 int index = glyph_index->start;
1544 if (!feature)
1545 return;
1547 while(index <= glyph_index->end)
1549 INT nextIndex;
1550 INT prevCount = *pcGlyphs;
1551 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1552 if (nextIndex > GSUB_E_NOGLYPH)
1554 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1555 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1556 index = nextIndex;
1558 else
1559 index++;
1563 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1565 int i = 0;
1566 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)))))
1567 i++;
1568 if (index + i <= end-1)
1569 return index + i;
1570 else
1571 return -1;
1574 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)
1576 INT index, nextIndex;
1577 INT count,g_offset;
1579 count = syllable->base - syllable->start;
1581 g_offset = 0;
1582 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1583 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1585 INT prevCount = *pcGlyphs;
1586 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1587 if (nextIndex > GSUB_E_NOGLYPH)
1589 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1590 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1591 g_offset += (*pcGlyphs - prevCount);
1594 index+=2;
1595 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1599 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)
1601 INT nextIndex;
1602 INT prevCount = *pcGlyphs;
1604 if (syllable->ralf >= 0)
1606 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1607 if (nextIndex > GSUB_E_NOGLYPH)
1609 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1610 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1615 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1617 int i = 0;
1618 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1619 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1620 is_consonant(lexical(pwChars[index+i+1])))))
1621 i++;
1622 if (index + i <= end-1)
1623 return index+i;
1624 else
1625 return -1;
1628 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)
1630 INT index, nextIndex;
1631 INT count, g_offset=0;
1632 INT ralf = syllable->ralf;
1634 count = syllable->end - syllable->base;
1636 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
1638 while (index >= 0)
1640 INT prevCount = *pcGlyphs;
1641 if (ralf >=0 && ralf < index)
1643 g_offset--;
1644 ralf = -1;
1647 if (!modern)
1649 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1650 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1651 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1654 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
1655 if (nextIndex > GSUB_E_NOGLYPH)
1657 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1658 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
1659 g_offset += (*pcGlyphs - prevCount);
1661 else if (!modern)
1663 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1664 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1665 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1668 index+=2;
1669 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
1673 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)
1675 int c;
1676 int overall_shift = 0;
1677 LoadedFeature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
1678 LoadedFeature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
1679 LoadedFeature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
1680 LoadedFeature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
1681 LoadedFeature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
1682 LoadedFeature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
1683 LoadedFeature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
1684 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
1685 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
1686 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
1687 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
1688 IndicSyllable glyph_indexs;
1690 for (c = 0; c < syllable_count; c++)
1692 int old_end;
1693 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
1694 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
1695 old_end = glyph_indexs.end;
1697 if (locl)
1699 TRACE("applying feature locl\n");
1700 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
1702 if (nukt)
1704 TRACE("applying feature nukt\n");
1705 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
1707 if (akhn)
1709 TRACE("applying feature akhn\n");
1710 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
1713 if (rphf)
1714 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
1715 if (rkrf)
1717 TRACE("applying feature rkrf\n");
1718 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
1720 if (pref)
1721 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
1722 if (blwf)
1724 if (!modern)
1725 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
1727 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
1730 if (half)
1731 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
1732 if (pstf)
1734 TRACE("applying feature pstf\n");
1735 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
1737 if (vatu)
1739 TRACE("applying feature vatu\n");
1740 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
1742 if (cjct)
1744 TRACE("applying feature cjct\n");
1745 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
1748 if (second_reorder)
1749 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
1751 overall_shift += glyph_indexs.end - old_end;
1755 static inline int unicode_lex(WCHAR c)
1757 int type;
1759 if (!c) return lex_Generic;
1760 if (c == 0x200D) return lex_ZWJ;
1761 if (c == 0x200C) return lex_ZWNJ;
1762 if (c == 0x00A0) return lex_NBSP;
1764 type = get_table_entry( indic_syllabic_table, c );
1766 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
1768 switch( type )
1770 case 0x0d07: /* Unknown */
1771 case 0x0e07: /* Unknwon */
1772 default: return lex_Generic;
1773 case 0x0001:
1774 case 0x0002:
1775 case 0x0011:
1776 case 0x0012:
1777 case 0x0013:
1778 case 0x0014: return lex_Modifier;
1779 case 0x0003:
1780 case 0x0009:
1781 case 0x000a:
1782 case 0x000b:
1783 case 0x000d:
1784 case 0x000e:
1785 case 0x000f:
1786 case 0x0010: return lex_Consonant;
1787 case 0x0004: return lex_Nukta;
1788 case 0x0005: return lex_Halant;
1789 case 0x0006:
1790 case 0x0008: return lex_Vowel;
1791 case 0x0007:
1792 case 0x0107: return lex_Matra_post;
1793 case 0x0207:
1794 case 0x0307: return lex_Matra_pre;
1795 case 0x0807:
1796 case 0x0907:
1797 case 0x0a07:
1798 case 0x0b07:
1799 case 0x0c07:
1800 case 0x0407: return lex_Composed_Vowel;
1801 case 0x0507: return lex_Matra_above;
1802 case 0x0607: return lex_Matra_below;
1803 case 0x000c: return lex_Ra;
1807 static int sinhala_lex(WCHAR c)
1809 switch (c)
1811 case 0x0DDA:
1812 case 0x0DDD:
1813 case 0x0DDC:
1814 case 0x0DDE: return lex_Matra_post;
1815 default:
1816 return unicode_lex(c);
1820 static const VowelComponents Sinhala_vowels[] = {
1821 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
1822 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
1823 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
1824 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
1825 {0x0000, {0x0000,0x0000,0x0}}};
1827 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1829 int cCount = cChars;
1830 int i;
1831 WCHAR *input;
1832 IndicSyllable *syllables = NULL;
1833 int syllable_count = 0;
1835 if (*pcGlyphs != cChars)
1837 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1838 return;
1841 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
1843 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1845 /* Step 1: Decompose multi part vowels */
1846 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
1848 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1850 /* Step 2: Reorder within Syllables */
1851 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
1852 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1854 /* Step 3: Strip dangling joiners */
1855 for (i = 0; i < cCount; i++)
1857 if ((input[i] == 0x200D || input[i] == 0x200C) &&
1858 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
1859 input[i] = 0x0020;
1862 /* Step 4: Base Form application to syllables */
1863 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1864 *pcGlyphs = cCount;
1865 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
1867 HeapFree(GetProcessHeap(),0,input);
1868 HeapFree(GetProcessHeap(),0,syllables);
1871 static int devanagari_lex(WCHAR c)
1873 switch (c)
1875 case 0x0930: return lex_Ra;
1876 default:
1877 return unicode_lex(c);
1881 static const ConsonantComponents Devanagari_consonants[] ={
1882 {{0x0928, 0x093C, 0x00000}, 0x0929},
1883 {{0x0930, 0x093C, 0x00000}, 0x0931},
1884 {{0x0933, 0x093C, 0x00000}, 0x0934},
1885 {{0x0915, 0x093C, 0x00000}, 0x0958},
1886 {{0x0916, 0x093C, 0x00000}, 0x0959},
1887 {{0x0917, 0x093C, 0x00000}, 0x095A},
1888 {{0x091C, 0x093C, 0x00000}, 0x095B},
1889 {{0x0921, 0x093C, 0x00000}, 0x095C},
1890 {{0x0922, 0x093C, 0x00000}, 0x095D},
1891 {{0x092B, 0x093C, 0x00000}, 0x095E},
1892 {{0x092F, 0x093C, 0x00000}, 0x095F}};
1894 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1896 int cCount = cChars;
1897 WCHAR *input;
1898 IndicSyllable *syllables = NULL;
1899 int syllable_count = 0;
1900 BOOL modern = get_GSUB_Indic2(psa, psc);
1902 if (*pcGlyphs != cChars)
1904 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1905 return;
1908 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1909 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1911 /* Step 1: Compose Consonant and Nukta */
1912 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
1913 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1915 /* Step 2: Reorder within Syllables */
1916 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
1917 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1918 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1919 *pcGlyphs = cCount;
1921 /* Step 3: Base Form application to syllables */
1922 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
1924 HeapFree(GetProcessHeap(),0,input);
1925 HeapFree(GetProcessHeap(),0,syllables);
1928 static int bengali_lex(WCHAR c)
1930 switch (c)
1932 case 0x09B0: return lex_Ra;
1933 default:
1934 return unicode_lex(c);
1938 static const VowelComponents Bengali_vowels[] = {
1939 {0x09CB, {0x09C7,0x09BE,0x0000}},
1940 {0x09CC, {0x09C7,0x09D7,0x0000}},
1941 {0x0000, {0x0000,0x0000,0x0000}}};
1943 static const ConsonantComponents Bengali_consonants[] = {
1944 {{0x09A4,0x09CD,0x200D}, 0x09CE},
1945 {{0x09A1,0x09BC,0x0000}, 0x09DC},
1946 {{0x09A2,0x09BC,0x0000}, 0x09DD},
1947 {{0x09AF,0x09BC,0x0000}, 0x09DF},
1948 {{0x0000,0x0000,0x0000}, 0x0000}};
1950 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1952 int cCount = cChars;
1953 WCHAR *input;
1954 IndicSyllable *syllables = NULL;
1955 int syllable_count = 0;
1956 BOOL modern = get_GSUB_Indic2(psa, psc);
1958 if (*pcGlyphs != cChars)
1960 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1961 return;
1964 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
1965 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1967 /* Step 1: Decompose Vowels and Compose Consonants */
1968 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
1969 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
1970 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1972 /* Step 2: Reorder within Syllables */
1973 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
1974 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1975 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1976 *pcGlyphs = cCount;
1978 /* Step 3: Initial form is only applied to the beginning of words */
1979 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
1981 if (cCount == 0 || input[cCount] == 0x0020) /* space */
1983 int index = cCount;
1984 int gCount = 1;
1985 if (index > 0) index++;
1987 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
1991 /* Step 4: Base Form application to syllables */
1992 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
1994 HeapFree(GetProcessHeap(),0,input);
1995 HeapFree(GetProcessHeap(),0,syllables);
1998 static int gurmukhi_lex(WCHAR c)
2000 if (c == 0x0A71)
2001 return lex_Modifier;
2002 else
2003 return unicode_lex(c);
2006 static const ConsonantComponents Gurmukhi_consonants[] = {
2007 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2008 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2009 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2010 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2011 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2012 {{0x0000,0x0000,0x0000}, 0x0000}};
2014 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2016 int cCount = cChars;
2017 WCHAR *input;
2018 IndicSyllable *syllables = NULL;
2019 int syllable_count = 0;
2020 BOOL modern = get_GSUB_Indic2(psa, psc);
2022 if (*pcGlyphs != cChars)
2024 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2025 return;
2028 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2029 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2031 /* Step 1: Compose Consonants */
2032 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2033 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2035 /* Step 2: Reorder within Syllables */
2036 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2037 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2038 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2039 *pcGlyphs = cCount;
2041 /* Step 3: Base Form application to syllables */
2042 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2044 HeapFree(GetProcessHeap(),0,input);
2045 HeapFree(GetProcessHeap(),0,syllables);
2048 static int gujarati_lex(WCHAR c)
2050 switch (c)
2052 case 0x0AB0: return lex_Ra;
2053 default:
2054 return unicode_lex(c);
2058 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2060 int cCount = cChars;
2061 WCHAR *input;
2062 IndicSyllable *syllables = NULL;
2063 int syllable_count = 0;
2064 BOOL modern = get_GSUB_Indic2(psa, psc);
2066 if (*pcGlyphs != cChars)
2068 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2069 return;
2072 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2073 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2075 /* Step 1: Reorder within Syllables */
2076 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2077 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2078 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2079 *pcGlyphs = cCount;
2081 /* Step 2: Base Form application to syllables */
2082 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2084 HeapFree(GetProcessHeap(),0,input);
2085 HeapFree(GetProcessHeap(),0,syllables);
2088 static int oriya_lex(WCHAR c)
2090 switch (c)
2092 case 0x0B30: return lex_Ra;
2093 default:
2094 return unicode_lex(c);
2098 static const VowelComponents Oriya_vowels[] = {
2099 {0x0B48, {0x0B47,0x0B56,0x0000}},
2100 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2101 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2102 {0x0000, {0x0000,0x0000,0x0000}}};
2104 static const ConsonantComponents Oriya_consonants[] = {
2105 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2106 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2107 {{0x0000,0x0000,0x0000}, 0x0000}};
2109 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2111 int cCount = cChars;
2112 WCHAR *input;
2113 IndicSyllable *syllables = NULL;
2114 int syllable_count = 0;
2115 BOOL modern = get_GSUB_Indic2(psa, psc);
2117 if (*pcGlyphs != cChars)
2119 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2120 return;
2123 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2124 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2126 /* Step 1: Decompose Vowels and Compose Consonants */
2127 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2128 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2129 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2131 /* Step 2: Reorder within Syllables */
2132 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2133 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2134 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2135 *pcGlyphs = cCount;
2137 /* Step 3: Base Form application to syllables */
2138 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2140 HeapFree(GetProcessHeap(),0,input);
2141 HeapFree(GetProcessHeap(),0,syllables);
2144 static int tamil_lex(WCHAR c)
2146 return unicode_lex(c);
2149 static const VowelComponents Tamil_vowels[] = {
2150 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2151 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2152 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2153 {0x0000, {0x0000,0x0000,0x0000}}};
2155 static const ConsonantComponents Tamil_consonants[] = {
2156 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2157 {{0x0000,0x0000,0x0000}, 0x0000}};
2159 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2161 int cCount = cChars;
2162 WCHAR *input;
2163 IndicSyllable *syllables = NULL;
2164 int syllable_count = 0;
2165 BOOL modern = get_GSUB_Indic2(psa, psc);
2167 if (*pcGlyphs != cChars)
2169 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2170 return;
2173 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2174 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2176 /* Step 1: Decompose Vowels and Compose Consonants */
2177 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2178 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2179 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2181 /* Step 2: Reorder within Syllables */
2182 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2183 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2184 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2185 *pcGlyphs = cCount;
2187 /* Step 3: Base Form application to syllables */
2188 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2190 HeapFree(GetProcessHeap(),0,input);
2191 HeapFree(GetProcessHeap(),0,syllables);
2194 static int telugu_lex(WCHAR c)
2196 switch (c)
2198 case 0x0C43:
2199 case 0x0C44: return lex_Modifier;
2200 default:
2201 return unicode_lex(c);
2205 static const VowelComponents Telugu_vowels[] = {
2206 {0x0C48, {0x0C46,0x0C56,0x0000}},
2207 {0x0000, {0x0000,0x0000,0x0000}}};
2209 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2211 int cCount = cChars;
2212 WCHAR *input;
2213 IndicSyllable *syllables = NULL;
2214 int syllable_count = 0;
2215 BOOL modern = get_GSUB_Indic2(psa, psc);
2217 if (*pcGlyphs != cChars)
2219 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2220 return;
2223 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2224 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2226 /* Step 1: Decompose Vowels */
2227 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2228 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2230 /* Step 2: Reorder within Syllables */
2231 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2232 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2233 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2234 *pcGlyphs = cCount;
2236 /* Step 3: Base Form application to syllables */
2237 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2239 HeapFree(GetProcessHeap(),0,input);
2240 HeapFree(GetProcessHeap(),0,syllables);
2243 static int kannada_lex(WCHAR c)
2245 switch (c)
2247 case 0x0CB0: return lex_Ra;
2248 default:
2249 return unicode_lex(c);
2253 static const VowelComponents Kannada_vowels[] = {
2254 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2255 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2256 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2257 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2258 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2259 {0x0000, {0x0000,0x0000,0x0000}}};
2261 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2263 int cCount = cChars;
2264 WCHAR *input;
2265 IndicSyllable *syllables = NULL;
2266 int syllable_count = 0;
2267 BOOL modern = get_GSUB_Indic2(psa, psc);
2269 if (*pcGlyphs != cChars)
2271 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2272 return;
2275 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2276 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2278 /* Step 1: Decompose Vowels */
2279 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2280 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2282 /* Step 2: Reorder within Syllables */
2283 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2284 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2285 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2286 *pcGlyphs = cCount;
2288 /* Step 3: Base Form application to syllables */
2289 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2291 HeapFree(GetProcessHeap(),0,input);
2292 HeapFree(GetProcessHeap(),0,syllables);
2295 static int malayalam_lex(WCHAR c)
2297 return unicode_lex(c);
2300 static const VowelComponents Malayalam_vowels[] = {
2301 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2302 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2303 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2304 {0x0000, {0x0000,0x0000,0x0000}}};
2306 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2308 int cCount = cChars;
2309 WCHAR *input;
2310 IndicSyllable *syllables = NULL;
2311 int syllable_count = 0;
2312 BOOL modern = get_GSUB_Indic2(psa, psc);
2314 if (*pcGlyphs != cChars)
2316 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2317 return;
2320 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2321 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2323 /* Step 1: Decompose Vowels */
2324 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2325 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2327 /* Step 2: Reorder within Syllables */
2328 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2329 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2330 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2331 *pcGlyphs = cCount;
2333 /* Step 3: Base Form application to syllables */
2334 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2336 HeapFree(GetProcessHeap(),0,input);
2337 HeapFree(GetProcessHeap(),0,syllables);
2340 static int khmer_lex(WCHAR c)
2342 return unicode_lex(c);
2345 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2347 int cCount = cChars;
2348 WCHAR *input;
2349 IndicSyllable *syllables = NULL;
2350 int syllable_count = 0;
2352 if (*pcGlyphs != cChars)
2354 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2355 return;
2358 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2359 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2361 /* Step 1: Reorder within Syllables */
2362 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2363 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2364 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2365 *pcGlyphs = cCount;
2367 /* Step 2: Base Form application to syllables */
2368 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2370 HeapFree(GetProcessHeap(),0,input);
2371 HeapFree(GetProcessHeap(),0,syllables);
2374 static inline BOOL mongolian_wordbreak(WCHAR chr)
2376 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2379 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2381 INT *context_shape;
2382 INT dirL;
2383 int i;
2385 if (*pcGlyphs != cChars)
2387 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2388 return;
2391 if (!psa->fLogicalOrder && psa->fRTL)
2392 dirL = -1;
2393 else
2394 dirL = 1;
2396 if (!psc->GSUB_Table)
2397 psc->GSUB_Table = load_gsub_table(hdc);
2399 if (!psc->GSUB_Table)
2400 return;
2402 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2404 for (i = 0; i < cChars; i++)
2406 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2408 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2409 context_shape[i] = Xn;
2410 else
2411 context_shape[i] = Xl;
2413 else
2415 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2416 context_shape[i] = Xr;
2417 else
2418 context_shape[i] = Xm;
2422 /* Contextual Shaping */
2423 i = 0;
2424 while(i < *pcGlyphs)
2426 INT nextIndex;
2427 INT prevCount = *pcGlyphs;
2428 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2429 if (nextIndex > GSUB_E_NOGLYPH)
2431 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2432 i = nextIndex;
2434 else
2435 i++;
2438 HeapFree(GetProcessHeap(),0,context_shape);
2441 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)
2443 int i,k;
2445 for (i = 0; i < cGlyphs; i++)
2447 int char_index[20];
2448 int char_count = 0;
2450 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2451 if (k>=0)
2453 for (; k < cChars && pwLogClust[k] == i; k++)
2454 char_index[char_count++] = k;
2457 if (char_count == 0)
2458 continue;
2460 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2462 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2463 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2465 else
2466 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2469 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2470 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2473 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 )
2475 int i,k;
2476 int initGlyph, finaGlyph;
2477 INT dirR, dirL;
2478 BYTE *spaces;
2480 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2481 memset(spaces,0,cGlyphs);
2483 if (!psa->fLogicalOrder && psa->fRTL)
2485 initGlyph = cGlyphs-1;
2486 finaGlyph = 0;
2487 dirR = 1;
2488 dirL = -1;
2490 else
2492 initGlyph = 0;
2493 finaGlyph = cGlyphs-1;
2494 dirR = -1;
2495 dirL = 1;
2498 for (i = 0; i < cGlyphs; i++)
2500 for (k = 0; k < cChars; k++)
2501 if (pwLogClust[k] == i)
2503 if (pwcChars[k] == 0x0020)
2504 spaces[i] = 1;
2508 for (i = 0; i < cGlyphs; i++)
2510 int char_index[20];
2511 int char_count = 0;
2512 BOOL isInit, isFinal;
2514 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2515 if (k>=0)
2517 for (; k < cChars && pwLogClust[k] == i; k++)
2518 char_index[char_count++] = k;
2521 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2522 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2524 if (char_count == 0)
2525 continue;
2527 if (char_count == 1)
2529 if (pwcChars[char_index[0]] == 0x0020) /* space */
2531 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2532 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2534 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2535 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2536 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2538 if (!isInit && !isFinal)
2539 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2540 else if (isInit)
2541 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2542 else
2543 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2545 else if (!isInit)
2547 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2548 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2549 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2550 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2551 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2552 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2553 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2554 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2555 else
2556 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2558 else if (!isInit && !isFinal)
2559 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2560 else
2561 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2563 else if (char_count == 2)
2565 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2566 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2567 else if (!isInit)
2568 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2569 else
2570 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2572 else if (!isInit && !isFinal)
2573 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2574 else
2575 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2578 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2579 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2580 HeapFree(GetProcessHeap(),0,spaces);
2583 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 )
2585 int i,k;
2586 int finaGlyph;
2587 INT dirL;
2588 BYTE *spaces;
2590 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2591 memset(spaces,0,cGlyphs);
2593 if (!psa->fLogicalOrder && psa->fRTL)
2595 finaGlyph = 0;
2596 dirL = -1;
2598 else
2600 finaGlyph = cGlyphs-1;
2601 dirL = 1;
2604 for (i = 0; i < cGlyphs; i++)
2606 for (k = 0; k < cChars; k++)
2607 if (pwLogClust[k] == i)
2609 if (pwcChars[k] == 0x0020)
2610 spaces[i] = 1;
2614 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2616 for (i = 0; i < cGlyphs; i++)
2618 int char_index[20];
2619 int char_count = 0;
2621 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2622 if (k>=0)
2624 for (; k < cChars && pwLogClust[k] == i; k++)
2625 char_index[char_count++] = k;
2628 if (char_count == 0)
2629 continue;
2631 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2633 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2634 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2636 else if (i == finaGlyph)
2637 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2638 else
2639 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2641 /* handle Thai SARA AM (U+0E33) differently than GDEF */
2642 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
2643 pGlyphProp[i].sva.fClusterStart = 0;
2646 HeapFree(GetProcessHeap(),0,spaces);
2647 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2649 /* Do not allow justification between marks and their base */
2650 for (i = 0; i < cGlyphs; i++)
2652 if (!pGlyphProp[i].sva.fClusterStart)
2653 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2657 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)
2659 int i,k;
2661 for (i = 0; i < cGlyphs; i++)
2663 int char_index[20];
2664 int char_count = 0;
2666 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2667 if (k>=0)
2669 for (; k < cChars && pwLogClust[k] == i; k++)
2670 char_index[char_count++] = k;
2673 if (char_count == 0)
2674 continue;
2676 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2678 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2679 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2681 else
2682 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2684 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2685 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2688 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)
2690 int i,k;
2692 for (i = 0; i < cGlyphs; i++)
2694 int char_index[20];
2695 int char_count = 0;
2697 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2698 if (k>=0)
2700 for (; k < cChars && pwLogClust[k] == i; k++)
2701 char_index[char_count++] = k;
2704 if (char_count == 0)
2705 continue;
2707 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2709 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2710 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2712 else
2713 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2715 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2716 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2718 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2719 for (i = 0; i < cGlyphs; i++)
2721 if (!pGlyphProp[i].sva.fClusterStart)
2723 pGlyphProp[i].sva.fDiacritic = 0;
2724 pGlyphProp[i].sva.fZeroWidth = 0;
2729 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)
2731 int i,k;
2733 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2734 for (i = 0; i < cGlyphs; i++)
2736 int char_index[20];
2737 int char_count = 0;
2739 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2740 if (k>=0)
2742 for (; k < cChars && pwLogClust[k] == i; k++)
2743 char_index[char_count++] = k;
2746 if (override_gsub)
2748 /* Most indic scripts do not set fDiacritic or fZeroWidth */
2749 pGlyphProp[i].sva.fDiacritic = FALSE;
2750 pGlyphProp[i].sva.fZeroWidth = FALSE;
2753 if (char_count == 0)
2754 continue;
2756 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2758 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2759 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2761 else
2762 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2764 pGlyphProp[i].sva.fClusterStart = 0;
2765 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2766 switch (lexical(pwcChars[char_index[k]]))
2768 case lex_Matra_pre:
2769 case lex_Matra_post:
2770 case lex_Matra_above:
2771 case lex_Matra_below:
2772 case lex_Modifier:
2773 case lex_Halant:
2774 break;
2775 case lex_ZWJ:
2776 case lex_ZWNJ:
2777 /* check for dangling joiners */
2778 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
2779 pGlyphProp[i].sva.fClusterStart = 1;
2780 else
2781 k = char_count;
2782 break;
2783 default:
2784 pGlyphProp[i].sva.fClusterStart = 1;
2785 break;
2789 if (use_syllables)
2791 IndicSyllable *syllables = NULL;
2792 int syllable_count = 0;
2793 BOOL modern = get_GSUB_Indic2(psa, psc);
2795 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
2797 for (i = 0; i < syllable_count; i++)
2799 int j;
2800 WORD g = pwLogClust[syllables[i].start];
2801 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
2803 if (pwLogClust[j] != g)
2805 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
2806 pwLogClust[j] = g;
2811 HeapFree(GetProcessHeap(), 0, syllables);
2814 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2817 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 )
2819 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
2822 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 )
2824 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
2827 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 )
2829 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
2832 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 )
2834 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
2837 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 )
2839 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
2842 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 )
2844 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
2847 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 )
2849 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
2852 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 )
2854 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
2857 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 )
2859 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
2862 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 )
2864 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
2867 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 )
2869 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
2872 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)
2874 if (ShapingData[psa->eScript].charGlyphPropProc)
2875 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2876 else
2877 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2880 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2882 if (!psc->GSUB_Table)
2883 psc->GSUB_Table = load_gsub_table(hdc);
2885 if (ShapingData[psa->eScript].contextProc)
2886 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2889 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)
2891 int i;
2892 INT dirL;
2894 if (!rpRangeProperties)
2895 return;
2897 if (!psc->GSUB_Table)
2898 psc->GSUB_Table = load_gsub_table(hdc);
2900 if (!psc->GSUB_Table)
2901 return;
2903 if (!psa->fLogicalOrder && psa->fRTL)
2904 dirL = -1;
2905 else
2906 dirL = 1;
2908 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
2910 if (rpRangeProperties->potfRecords[i].lParameter > 0)
2911 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
2915 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
2917 const TEXTRANGE_PROPERTIES *rpRangeProperties;
2918 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
2920 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
2923 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
2925 LoadedFeature *feature;
2926 int i;
2928 if (!ShapingData[psa->eScript].requiredFeatures)
2929 return S_OK;
2931 if (!psc->GSUB_Table)
2932 psc->GSUB_Table = load_gsub_table(hdc);
2934 /* we need to have at least one of the required features */
2935 i = 0;
2936 while (ShapingData[psa->eScript].requiredFeatures[i])
2938 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
2939 if (feature)
2940 return S_OK;
2941 i++;
2944 return USP_E_SCRIPT_NOT_IN_FONT;
2947 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
2948 SCRIPT_ANALYSIS *psa, int cMaxTags,
2949 OPENTYPE_TAG *pScriptTags, int *pcTags)
2951 HRESULT hr;
2952 OPENTYPE_TAG searching = 0x00000000;
2954 if (!psc->GSUB_Table)
2955 psc->GSUB_Table = load_gsub_table(hdc);
2957 if (psa && scriptInformation[psa->eScript].scriptTag)
2958 searching = scriptInformation[psa->eScript].scriptTag;
2960 hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL);
2961 if (FAILED(hr))
2962 *pcTags = 0;
2963 return hr;
2966 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
2967 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2968 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
2969 int *pcTags)
2971 HRESULT hr;
2972 OPENTYPE_TAG searching = 0x00000000;
2973 BOOL fellback = FALSE;
2975 if (!psc->GSUB_Table)
2976 psc->GSUB_Table = load_gsub_table(hdc);
2978 if (psa && psc->userLang != 0)
2979 searching = psc->userLang;
2981 hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL);
2982 if (FAILED(hr))
2984 fellback = TRUE;
2985 hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL);
2988 if (FAILED(hr) || fellback)
2989 *pcTags = 0;
2990 if (SUCCEEDED(hr) && fellback && psa)
2991 hr = E_INVALIDARG;
2992 return hr;
2995 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
2996 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2997 OPENTYPE_TAG tagLangSys, int cMaxTags,
2998 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3000 HRESULT hr;
3001 BOOL filter = FALSE;
3003 if (!psc->GSUB_Table)
3004 psc->GSUB_Table = load_gsub_table(hdc);
3006 if (psa && scriptInformation[psa->eScript].scriptTag)
3008 FIXME("Filtering not implemented\n");
3009 filter = TRUE;
3012 hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL);
3014 if (FAILED(hr))
3015 *pcTags = 0;
3016 return hr;