usp10: Corrections for ShapeCharGlyphProp_Thai.
[wine/multimedia.git] / dlls / usp10 / shape.c
blob36f6854c7e61e1911be9bb4a5a8853673fab698e
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #define FIRST_ARABIC_CHAR 0x0600
39 #define LAST_ARABIC_CHAR 0x06ff
41 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
42 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
64 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
66 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
67 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
68 static void ShapeCharGlyphProp_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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
78 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 );
79 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 );
80 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 );
81 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 );
83 extern const unsigned short indic_syllabic_table[];
84 extern const unsigned short wine_shaping_table[];
85 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
87 enum joining_types {
88 jtU,
89 jtT,
90 jtR,
91 jtL,
92 jtD,
93 jtC
96 enum joined_forms {
97 Xn=0,
98 Xr,
99 Xl,
101 /* Syriac Alaph */
102 Afj,
103 Afn,
107 typedef struct tagVowelComponents
109 WCHAR base;
110 WCHAR parts[3];
111 } VowelComponents;
113 typedef struct tagConsonantComponents
115 WCHAR parts[3];
116 WCHAR output;
117 } ConsonantComponents;
119 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
121 typedef int (*combining_lexical_function)(WCHAR c);
123 /* the orders of joined_forms and contextual_features need to line up */
124 static const char* contextual_features[] =
126 "isol",
127 "fina",
128 "init",
129 "medi",
130 /* Syriac Alaph */
131 "med2",
132 "fin2",
133 "fin3"
136 static OPENTYPE_FEATURE_RECORD standard_features[] =
138 { MS_MAKE_TAG('c','c','m','p'), 1},
139 { MS_MAKE_TAG('l','o','c','l'), 1},
142 static OPENTYPE_FEATURE_RECORD latin_features[] =
144 { MS_MAKE_TAG('l','i','g','a'), 1},
145 { MS_MAKE_TAG('c','l','i','g'), 1},
148 static OPENTYPE_FEATURE_RECORD arabic_features[] =
150 { MS_MAKE_TAG('r','l','i','g'), 1},
151 { MS_MAKE_TAG('c','a','l','t'), 1},
152 { MS_MAKE_TAG('l','i','g','a'), 1},
153 { MS_MAKE_TAG('d','l','i','g'), 1},
154 { MS_MAKE_TAG('c','s','w','h'), 1},
155 { MS_MAKE_TAG('m','s','e','t'), 1},
158 static const char* required_arabic_features[] =
160 "fina",
161 "init",
162 "medi",
163 "rlig",
164 NULL
167 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
169 { MS_MAKE_TAG('d','l','i','g'), 0},
172 static OPENTYPE_FEATURE_RECORD syriac_features[] =
174 { MS_MAKE_TAG('r','l','i','g'), 1},
175 { MS_MAKE_TAG('c','a','l','t'), 1},
176 { MS_MAKE_TAG('l','i','g','a'), 1},
177 { MS_MAKE_TAG('d','l','i','g'), 1},
180 static const char* required_syriac_features[] =
182 "fina",
183 "fin2",
184 "fin3",
185 "init",
186 "medi",
187 "med2",
188 "rlig",
189 NULL
192 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
194 /* Presentation forms */
195 { MS_MAKE_TAG('b','l','w','s'), 1},
196 { MS_MAKE_TAG('a','b','v','s'), 1},
197 { MS_MAKE_TAG('p','s','t','s'), 1},
200 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
202 { MS_MAKE_TAG('a','b','v','s'), 1},
203 { MS_MAKE_TAG('b','l','w','s'), 1},
206 static OPENTYPE_FEATURE_RECORD phags_features[] =
208 { MS_MAKE_TAG('a','b','v','s'), 1},
209 { MS_MAKE_TAG('b','l','w','s'), 1},
210 { MS_MAKE_TAG('c','a','l','t'), 1},
213 static OPENTYPE_FEATURE_RECORD thai_features[] =
215 { MS_MAKE_TAG('c','c','m','p'), 1},
218 static const char* required_lao_features[] =
220 "ccmp",
221 NULL
224 static const char* required_devanagari_features[] =
226 "nukt",
227 "akhn",
228 "rphf",
229 "blwf",
230 "half",
231 "vatu",
232 "pres",
233 "abvs",
234 "blws",
235 "psts",
236 "haln",
237 NULL
240 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
242 { MS_MAKE_TAG('p','r','e','s'), 1},
243 { MS_MAKE_TAG('a','b','v','s'), 1},
244 { MS_MAKE_TAG('b','l','w','s'), 1},
245 { MS_MAKE_TAG('p','s','t','s'), 1},
246 { MS_MAKE_TAG('h','a','l','n'), 1},
247 { MS_MAKE_TAG('c','a','l','t'), 1},
250 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
252 { MS_MAKE_TAG('l','i','g','a'), 1},
253 { MS_MAKE_TAG('c','l','i','g'), 1},
256 static const char* required_bengali_features[] =
258 "nukt",
259 "akhn",
260 "rphf",
261 "blwf",
262 "half",
263 "vatu",
264 "pstf",
265 "init",
266 "abvs",
267 "blws",
268 "psts",
269 "haln",
270 NULL
273 static const char* required_gurmukhi_features[] =
275 "nukt",
276 "akhn",
277 "rphf",
278 "blwf",
279 "half",
280 "pstf",
281 "vatu",
282 "cjct",
283 "pres",
284 "abvs",
285 "blws",
286 "psts",
287 "haln",
288 "calt",
289 NULL
292 static const char* required_oriya_features[] =
294 "nukt",
295 "akhn",
296 "rphf",
297 "blwf",
298 "pstf",
299 "cjct",
300 "pres",
301 "abvs",
302 "blws",
303 "psts",
304 "haln",
305 "calt",
306 NULL
309 static const char* required_tamil_features[] =
311 "nukt",
312 "akhn",
313 "rphf",
314 "pref",
315 "half",
316 "pres",
317 "abvs",
318 "blws",
319 "psts",
320 "haln",
321 "calt",
322 NULL
325 static const char* required_telugu_features[] =
327 "nukt",
328 "akhn",
329 "rphf",
330 "pref",
331 "half",
332 "pstf",
333 "cjct",
334 "pres",
335 "abvs",
336 "blws",
337 "psts",
338 "haln",
339 "calt",
340 NULL
343 static OPENTYPE_FEATURE_RECORD khmer_features[] =
345 { MS_MAKE_TAG('p','r','e','s'), 1},
346 { MS_MAKE_TAG('b','l','w','s'), 1},
347 { MS_MAKE_TAG('a','b','v','s'), 1},
348 { MS_MAKE_TAG('p','s','t','s'), 1},
349 { MS_MAKE_TAG('c','l','i','g'), 1},
352 static const char* required_khmer_features[] =
354 "pref",
355 "blwf",
356 "abvf",
357 "pstf",
358 "pres",
359 "blws",
360 "abvs",
361 "psts",
362 "clig",
363 NULL
366 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
368 { MS_MAKE_TAG('c','c','m','p'), 1},
369 { MS_MAKE_TAG('l','o','c','l'), 1},
370 { MS_MAKE_TAG('c','a','l','t'), 1},
371 { MS_MAKE_TAG('l','i','g','a'), 1},
374 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
376 { MS_MAKE_TAG('c','c','m','p'), 1},
377 { MS_MAKE_TAG('l','o','c','l'), 1},
378 { MS_MAKE_TAG('c','a','l','t'), 1},
379 { MS_MAKE_TAG('r','l','i','g'), 1},
382 typedef struct ScriptShapeDataTag {
383 TEXTRANGE_PROPERTIES defaultTextRange;
384 const char** requiredFeatures;
385 OPENTYPE_TAG newOtTag;
386 ContextualShapingProc contextProc;
387 ShapeCharGlyphPropProc charGlyphPropProc;
388 } ScriptShapeData;
390 /* in order of scripts */
391 static const ScriptShapeData ShapingData[] =
393 {{ standard_features, 2}, NULL, 0, NULL, NULL},
394 {{ latin_features, 2}, NULL, 0, NULL, NULL},
395 {{ latin_features, 2}, NULL, 0, NULL, NULL},
396 {{ latin_features, 2}, NULL, 0, NULL, NULL},
397 {{ standard_features, 2}, NULL, 0, NULL, NULL},
398 {{ latin_features, 2}, NULL, 0, NULL, NULL},
399 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
400 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
401 {{ hebrew_features, 1}, NULL, 0, ContextualShape_Hebrew, NULL},
402 {{ syriac_features, 4}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
403 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
404 {{ NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
405 {{ standard_features, 2}, NULL, 0, NULL, NULL},
406 {{ standard_features, 2}, NULL, 0, NULL, NULL},
407 {{ standard_features, 2}, NULL, 0, NULL, NULL},
408 {{ standard_features, 2}, NULL, 0, NULL, NULL},
409 {{ sinhala_features, 3}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
410 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
411 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
412 {{ phags_features, 3}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
413 {{ thai_features, 1}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
414 {{ thai_features, 1}, NULL, 0, ContextualShape_Thai, NULL},
415 {{ thai_features, 1}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
416 {{ thai_features, 1}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
417 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
418 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
419 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
420 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
421 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
422 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
423 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
424 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
425 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
426 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
427 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
428 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
429 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
430 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
431 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
432 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
433 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
434 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
435 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
436 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
437 {{ standard_features, 2}, NULL, 0, NULL, NULL},
438 {{ latin_features, 2}, NULL, 0, NULL, NULL},
439 {{ standard_features, 2}, NULL, 0, NULL, NULL},
440 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
441 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
442 {{ standard_features, 2}, NULL, 0, NULL, NULL},
443 {{ standard_features, 2}, NULL, 0, NULL, NULL},
444 {{ standard_features, 2}, NULL, 0, NULL, NULL},
445 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
446 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
447 {{ NULL, 0}, NULL, 0, NULL, NULL},
448 {{ NULL, 0}, NULL, 0, NULL, NULL},
449 {{ NULL, 0}, NULL, 0, NULL, NULL},
450 {{ NULL, 0}, NULL, 0, NULL, NULL},
451 {{ NULL, 0}, NULL, 0, NULL, NULL},
452 {{ NULL, 0}, NULL, 0, NULL, NULL},
453 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
454 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
455 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
456 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, 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 {{ NULL, 0}, NULL, 0, NULL, NULL},
469 {{ NULL, 0}, NULL, 0, NULL, NULL},
470 {{ NULL, 0}, NULL, 0, NULL, NULL},
471 {{ NULL, 0}, NULL, 0, NULL, NULL},
472 {{ hebrew_features, 1}, NULL, 0, ContextualShape_Hebrew, NULL},
473 {{ latin_features, 2}, NULL, 0, NULL, NULL},
474 {{ thai_features, 1}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
477 extern scriptData scriptInformation[];
479 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
481 int i;
482 int out_index = GSUB_E_NOGLYPH;
484 TRACE("%i lookups\n", feature->lookup_count);
485 for (i = 0; i < feature->lookup_count; i++)
487 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
488 if (out_index != GSUB_E_NOGLYPH)
489 break;
491 if (out_index == GSUB_E_NOGLYPH)
492 TRACE("lookups found no glyphs\n");
493 else
495 int out2;
496 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
497 if (out2!=GSUB_E_NOGLYPH)
498 out_index = out2;
500 return out_index;
503 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
505 UINT charset;
507 if (psc->userScript != 0)
509 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
510 return ShapingData[psa->eScript].newOtTag;
511 else
512 return psc->userScript;
515 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
516 return ShapingData[psa->eScript].newOtTag;
518 if (scriptInformation[psa->eScript].scriptTag)
519 return scriptInformation[psa->eScript].scriptTag;
522 * fall back to the font charset
524 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
525 switch (charset)
527 case ANSI_CHARSET:
528 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
529 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
530 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
531 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
532 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
533 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
534 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
535 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
536 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
537 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
538 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
539 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
540 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
541 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
542 default: return MS_MAKE_TAG('l','a','t','n');
546 static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
548 LoadedFeature *feature = NULL;
550 if (psc->GSUB_Table)
552 int attempt = 2;
553 OPENTYPE_TAG tags;
554 OPENTYPE_TAG language;
555 OPENTYPE_TAG script;
556 int cTags;
560 script = get_opentype_script(hdc,psa,psc,(attempt==2));
561 if (psc->userLang != 0)
562 language = psc->userLang;
563 else
564 language = MS_MAKE_TAG('d','f','l','t');
565 attempt--;
567 OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
569 } while(attempt && !feature);
571 /* try in the default (latin) table */
572 if (!feature)
573 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);
576 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
577 return feature;
580 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)
582 LoadedFeature *feature;
584 feature = load_GSUB_feature(hdc, psa, psc, feat);
585 if (!feature)
586 return GSUB_E_NOFEATURE;
588 TRACE("applying feature %s\n",feat);
589 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
592 static VOID *load_gsub_table(HDC hdc)
594 VOID* GSUB_Table = NULL;
595 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
596 if (length != GDI_ERROR)
598 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
599 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
600 TRACE("Loaded GSUB table of %i bytes\n",length);
602 return GSUB_Table;
605 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)
607 WORD *glyphs;
608 INT glyph_count = count;
609 INT rc;
611 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
612 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
613 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
614 if (rc > GSUB_E_NOGLYPH)
615 rc = count - glyph_count;
616 else
617 rc = 0;
619 HeapFree(GetProcessHeap(),0,glyphs);
620 return rc;
623 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
625 int i;
627 for (i = 0; i < cGlyphs; i++)
629 if (!pGlyphProp[i].sva.fClusterStart)
631 int j;
632 for (j = 0; j < cChars; j++)
634 if (pwLogClust[j] == i)
636 int k = j;
637 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
638 k-=1;
639 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
640 pwLogClust[j] = pwLogClust[k];
647 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
649 if (changeCount == 0)
650 return;
651 else
653 int i;
654 int target_glyph = nextIndex - write_dir;
655 int seeking_glyph;
656 int target_index = -1;
657 int replacing_glyph = -1;
658 int changed = 0;
659 int top_logclust = 0;
661 if (changeCount > 0)
663 if (write_dir > 0)
664 target_glyph = nextIndex - changeCount;
665 else
666 target_glyph = nextIndex + (changeCount + 1);
669 seeking_glyph = target_glyph;
670 for (i = 0; i < chars; i++)
671 if (pwLogClust[i] > top_logclust)
672 top_logclust = pwLogClust[i];
674 do {
675 if (write_dir > 0)
676 for (i = 0; i < chars; i++)
678 if (pwLogClust[i] == seeking_glyph)
680 target_index = i;
681 break;
684 else
685 for (i = chars - 1; i >= 0; i--)
687 if (pwLogClust[i] == seeking_glyph)
689 target_index = i;
690 break;
693 if (target_index == -1)
694 seeking_glyph ++;
696 while (target_index == -1 && seeking_glyph <= top_logclust);
698 if (target_index == -1)
700 ERR("Unable to find target glyph\n");
701 return;
704 if (changeCount < 0)
706 /* merge glyphs */
707 for(i = target_index; i < chars && i >= 0; i+=write_dir)
709 if (pwLogClust[i] == target_glyph)
710 continue;
711 if(pwLogClust[i] == replacing_glyph)
712 pwLogClust[i] = target_glyph;
713 else
715 changed--;
716 if (changed >= changeCount)
718 replacing_glyph = pwLogClust[i];
719 pwLogClust[i] = target_glyph;
721 else
722 break;
726 /* renumber trailing indexes*/
727 for(i = target_index; i < chars && i >= 0; i+=write_dir)
729 if (pwLogClust[i] != target_glyph)
730 pwLogClust[i] += changeCount;
733 else
735 for(i = target_index; i < chars && i >= 0; i+=write_dir)
736 pwLogClust[i] += changeCount;
741 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 )
743 if (psc->GSUB_Table)
745 LoadedFeature *feature;
746 int lookup_index;
748 feature = load_GSUB_feature(hdc, psa, psc, feat);
749 if (!feature)
750 return GSUB_E_NOFEATURE;
752 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
753 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
755 int i;
757 if (write_dir > 0)
758 i = 0;
759 else
760 i = *pcGlyphs-1;
761 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
762 while(i < *pcGlyphs && i >= 0)
764 INT nextIndex;
765 INT prevCount = *pcGlyphs;
767 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
768 if (*pcGlyphs != prevCount)
770 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
771 i = nextIndex;
773 else
774 i+=write_dir;
777 return *pcGlyphs;
779 return GSUB_E_NOFEATURE;
782 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
784 OPENTYPE_TAG tag;
785 HRESULT hr;
786 int count = 0;
788 hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL);
790 return(SUCCEEDED(hr));
793 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
795 int i;
796 for (i = *pcGlyphs; i>=index; i--)
797 pwGlyphs[i+1] = pwGlyphs[i];
798 pwGlyphs[index] = glyph;
799 *pcGlyphs = *pcGlyphs+1;
800 if (write_dir < 0)
801 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
802 else
803 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
806 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)
808 CHAR *context_type;
809 int i,g;
810 WCHAR invalid = 0x25cc;
811 WORD invalid_glyph;
813 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
815 /* Mark invalid combinations */
816 for (i = 0; i < cChars; i++)
817 context_type[i] = lex(pwcChars[i]);
819 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
820 for (i = 1, g=1; i < cChars; i++, g++)
822 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
824 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
825 g++;
829 HeapFree(GetProcessHeap(),0,context_type);
832 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
834 if (i + delta < 0)
835 return 0;
836 if ( i+ delta >= cchLen)
837 return 0;
839 i += delta;
841 return chars[i];
844 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
846 if (i + delta < 0)
848 if (psa->fLinkBefore)
849 return jtR;
850 else
851 return jtU;
853 if ( i+ delta >= cchLen)
855 if (psa->fLinkAfter)
856 return jtL;
857 else
858 return jtU;
861 i += delta;
863 if (context_type[i] == jtT)
864 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
865 else
866 return context_type[i];
869 static inline BOOL right_join_causing(CHAR joining_type)
871 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
874 static inline BOOL left_join_causing(CHAR joining_type)
876 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
879 static inline BOOL word_break_causing(WCHAR chr)
881 /* we are working within a string of characters already guareented to
882 be within one script, Syriac, so we do not worry about any character
883 other than the space character outside of that range */
884 return (chr == 0 || chr == 0x20 );
887 static int combining_lexical_Arabic(WCHAR c)
889 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
891 switch(c)
893 case 0x064B:
894 case 0x064C:
895 case 0x064E:
896 case 0x064F:
897 case 0x0652:
898 case 0x0657:
899 case 0x0658:
900 case 0x06E1: return Arab_DIAC1; break;
901 case 0x064D:
902 case 0x0650:
903 case 0x0656: return Arab_DIAC2; break;
904 case 0x0651: return Arab_DIAC3; break;
905 case 0x0610:
906 case 0x0611:
907 case 0x0612:
908 case 0x0613:
909 case 0x0614:
910 case 0x0659:
911 case 0x06D6:
912 case 0x06DC:
913 case 0x06DF:
914 case 0x06E0:
915 case 0x06E2:
916 case 0x06E4:
917 case 0x06E7:
918 case 0x06E8:
919 case 0x06EB:
920 case 0x06EC: return Arab_DIAC4; break;
921 case 0x06E3:
922 case 0x06EA:
923 case 0x06ED: return Arab_DIAC5; break;
924 case 0x0670: return Arab_DIAC6; break;
925 case 0x0653: return Arab_DIAC7; break;
926 case 0x0655:
927 case 0x0654: return Arab_DIAC8; break;
928 default: return Arab_Norm;
933 * ContextualShape_Arabic
935 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
937 CHAR *context_type;
938 INT *context_shape;
939 INT dirR, dirL;
940 int i;
942 if (*pcGlyphs != cChars)
944 ERR("Number of Glyphs and Chars need to match at the beginning\n");
945 return;
948 if (!psa->fLogicalOrder && psa->fRTL)
950 dirR = 1;
951 dirL = -1;
953 else
955 dirR = -1;
956 dirL = 1;
959 if (!psc->GSUB_Table)
960 psc->GSUB_Table = load_gsub_table(hdc);
962 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
963 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
965 for (i = 0; i < cChars; i++)
966 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
968 for (i = 0; i < cChars; i++)
970 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
971 context_shape[i] = Xr;
972 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
973 context_shape[i] = Xl;
974 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)))
975 context_shape[i] = Xm;
976 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
977 context_shape[i] = Xr;
978 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
979 context_shape[i] = Xl;
980 else
981 context_shape[i] = Xn;
984 /* Contextual Shaping */
985 i = 0;
986 while(i < *pcGlyphs)
988 BOOL shaped = FALSE;
990 if (psc->GSUB_Table)
992 INT nextIndex;
993 INT prevCount = *pcGlyphs;
994 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
995 if (nextIndex > GSUB_E_NOGLYPH)
997 i = nextIndex;
998 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1000 shaped = (nextIndex > GSUB_E_NOGLYPH);
1003 if (!shaped)
1005 if (context_shape[i] == Xn)
1007 WORD newGlyph = pwOutGlyphs[i];
1008 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1010 /* fall back to presentation form B */
1011 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1012 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1013 pwOutGlyphs[i] = newGlyph;
1016 i++;
1020 HeapFree(GetProcessHeap(),0,context_shape);
1021 HeapFree(GetProcessHeap(),0,context_type);
1023 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1026 static int combining_lexical_Hebrew(WCHAR c)
1028 enum {Hebr_Norm=0, Hebr_DIAC, Hebr_CANT1, Hebr_CANT2, Hebr_CANT3, Hebr_CANT4, Hebr_CANT5, Hebr_CANT6, Hebr_CANT7, Hebr_CANT8, Hebr_CANT9, Hebr_CANT10, Hebr_DAGESH, Hebr_DOTABV, Hebr_HOLAM, Hebr_METEG, Hebr_PATAH, Hebr_QAMATS, Hebr_RAFE, Hebr_SHINSIN};
1030 switch(c)
1032 case 0x05B0:
1033 case 0x05B1:
1034 case 0x05B2:
1035 case 0x05B3:
1036 case 0x05B4:
1037 case 0x05B5:
1038 case 0x05B6:
1039 case 0x05BB: return Hebr_DIAC; break;
1040 case 0x0599:
1041 case 0x05A1:
1042 case 0x05A9:
1043 case 0x05AE: return Hebr_CANT1; break;
1044 case 0x0597:
1045 case 0x05A8:
1046 case 0x05AC: return Hebr_CANT2; break;
1047 case 0x0592:
1048 case 0x0593:
1049 case 0x0594:
1050 case 0x0595:
1051 case 0x05A7:
1052 case 0x05AB: return Hebr_CANT3; break;
1053 case 0x0598:
1054 case 0x059C:
1055 case 0x059E:
1056 case 0x059F: return Hebr_CANT4; break;
1057 case 0x059D:
1058 case 0x05A0: return Hebr_CANT5; break;
1059 case 0x059B:
1060 case 0x05A5: return Hebr_CANT6; break;
1061 case 0x0591:
1062 case 0x05A3:
1063 case 0x05A6: return Hebr_CANT7; break;
1064 case 0x0596:
1065 case 0x05A4:
1066 case 0x05AA: return Hebr_CANT8; break;
1067 case 0x059A:
1068 case 0x05AD: return Hebr_CANT9; break;
1069 case 0x05AF: return Hebr_CANT10; break;
1070 case 0x05BC: return Hebr_DAGESH; break;
1071 case 0x05C4: return Hebr_DOTABV; break;
1072 case 0x05B9: return Hebr_HOLAM; break;
1073 case 0x05BD: return Hebr_METEG; break;
1074 case 0x05B7: return Hebr_PATAH; break;
1075 case 0x05B8: return Hebr_QAMATS; break;
1076 case 0x05BF: return Hebr_RAFE; break;
1077 case 0x05C1:
1078 case 0x05C2: return Hebr_SHINSIN; break;
1079 default: return Hebr_Norm;
1083 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1085 INT dirL;
1087 if (*pcGlyphs != cChars)
1089 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1090 return;
1093 if (!psa->fLogicalOrder && psa->fRTL)
1094 dirL = -1;
1095 else
1096 dirL = 1;
1098 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1102 * ContextualShape_Syriac
1105 static int combining_lexical_Syriac(WCHAR c)
1107 enum {Syriac_Norm=0, Syriac_DIAC1, Syriac_DIAC2, Syriac_DIAC3, Syriac_DIAC4, Syriac_DIAC5, Syriac_DIAC6, Syriac_DIAC7, Syriac_DIAC8, Syriac_DIAC9, Syriac_DIAC10, Syriac_DIAC11, Syriac_DIAC12, Syriac_DIAC13, Syriac_DIAC14, Syriac_DIAC15, Syriac_DIAC16, Syriac_DIAC17};
1109 switch(c)
1111 case 0x730:
1112 case 0x733:
1113 case 0x736:
1114 case 0x73A:
1115 case 0x73D: return Syriac_DIAC1; break;
1116 case 0x731:
1117 case 0x734:
1118 case 0x737:
1119 case 0x73B:
1120 case 0x73E: return Syriac_DIAC2; break;
1121 case 0x740:
1122 case 0x749:
1123 case 0x74A: return Syriac_DIAC3; break;
1124 case 0x732:
1125 case 0x735:
1126 case 0x73F: return Syriac_DIAC4; break;
1127 case 0x738:
1128 case 0x739:
1129 case 0x73C: return Syriac_DIAC5; break;
1130 case 0x741:
1131 case 0x30A: return Syriac_DIAC6; break;
1132 case 0x742:
1133 case 0x325: return Syriac_DIAC7; break;
1134 case 0x747:
1135 case 0x303: return Syriac_DIAC8; break;
1136 case 0x748:
1137 case 0x32D:
1138 case 0x32E:
1139 case 0x330:
1140 case 0x331: return Syriac_DIAC9; break;
1141 case 0x308: return Syriac_DIAC10; break;
1142 case 0x304: return Syriac_DIAC11; break;
1143 case 0x307: return Syriac_DIAC12; break;
1144 case 0x323: return Syriac_DIAC13; break;
1145 case 0x743: return Syriac_DIAC14; break;
1146 case 0x744: return Syriac_DIAC15; break;
1147 case 0x745: return Syriac_DIAC16; break;
1148 case 0x746: return Syriac_DIAC17; break;
1149 default: return Syriac_Norm;
1153 #define ALAPH 0x710
1154 #define DALATH 0x715
1155 #define RISH 0x72A
1157 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1159 CHAR *context_type;
1160 INT *context_shape;
1161 INT dirR, dirL;
1162 int i;
1164 if (*pcGlyphs != cChars)
1166 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1167 return;
1170 if (!psa->fLogicalOrder && psa->fRTL)
1172 dirR = 1;
1173 dirL = -1;
1175 else
1177 dirR = -1;
1178 dirL = 1;
1181 if (!psc->GSUB_Table)
1182 psc->GSUB_Table = load_gsub_table(hdc);
1184 if (!psc->GSUB_Table)
1185 return;
1187 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1188 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1190 for (i = 0; i < cChars; i++)
1191 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1193 for (i = 0; i < cChars; i++)
1195 if (pwcChars[i] == ALAPH)
1197 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1199 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1200 context_shape[i] = Afj;
1201 else if ( rchar != DALATH && rchar != RISH &&
1202 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1203 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1204 context_shape[i] = Afn;
1205 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1206 context_shape[i] = Afx;
1207 else
1208 context_shape[i] = Xn;
1210 else if (context_type[i] == jtR &&
1211 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1212 context_shape[i] = Xr;
1213 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1214 context_shape[i] = Xl;
1215 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)))
1216 context_shape[i] = Xm;
1217 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1218 context_shape[i] = Xr;
1219 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1220 context_shape[i] = Xl;
1221 else
1222 context_shape[i] = Xn;
1225 /* Contextual Shaping */
1226 i = 0;
1227 while(i < *pcGlyphs)
1229 INT nextIndex;
1230 INT prevCount = *pcGlyphs;
1231 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1232 if (nextIndex > GSUB_E_NOGLYPH)
1234 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1235 i = nextIndex;
1237 else
1238 i++;
1241 HeapFree(GetProcessHeap(),0,context_shape);
1242 HeapFree(GetProcessHeap(),0,context_type);
1244 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1247 static int combining_lexical_Thaana(WCHAR c)
1249 enum {Thaana_Norm=0, Thaana_FILI};
1251 switch(c)
1253 case 0x7A6:
1254 case 0x7A7:
1255 case 0x7A8:
1256 case 0x7A9:
1257 case 0x7AA:
1258 case 0x7AB:
1259 case 0x7AC:
1260 case 0x7AD:
1261 case 0x7AE:
1262 case 0x7AF: return Thaana_FILI; break;
1263 default: return Thaana_Norm;
1267 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1269 INT dirL;
1271 if (*pcGlyphs != cChars)
1273 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1274 return;
1277 if (!psa->fLogicalOrder && psa->fRTL)
1278 dirL = -1;
1279 else
1280 dirL = 1;
1282 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1286 * ContextualShape_Phags_pa
1289 #define phags_pa_CANDRABINDU 0xA873
1290 #define phags_pa_START 0xA840
1291 #define phags_pa_END 0xA87F
1293 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1295 INT *context_shape;
1296 INT dirR, dirL;
1297 int i;
1299 if (*pcGlyphs != cChars)
1301 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1302 return;
1305 if (!psa->fLogicalOrder && psa->fRTL)
1307 dirR = 1;
1308 dirL = -1;
1310 else
1312 dirR = -1;
1313 dirL = 1;
1316 if (!psc->GSUB_Table)
1317 psc->GSUB_Table = load_gsub_table(hdc);
1319 if (!psc->GSUB_Table)
1320 return;
1322 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1324 for (i = 0; i < cChars; i++)
1326 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1328 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1329 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1330 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1331 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1333 if (jrchar && jlchar)
1334 context_shape[i] = Xm;
1335 else if (jrchar)
1336 context_shape[i] = Xr;
1337 else if (jlchar)
1338 context_shape[i] = Xl;
1339 else
1340 context_shape[i] = Xn;
1342 else
1343 context_shape[i] = -1;
1346 /* Contextual Shaping */
1347 i = 0;
1348 while(i < *pcGlyphs)
1350 if (context_shape[i] >= 0)
1352 INT nextIndex;
1353 INT prevCount = *pcGlyphs;
1354 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1355 if (nextIndex > GSUB_E_NOGLYPH)
1357 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1358 i = nextIndex;
1360 else
1361 i++;
1363 else
1364 i++;
1367 HeapFree(GetProcessHeap(),0,context_shape);
1370 static int combining_lexical_Thai(WCHAR c)
1372 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1374 switch(c)
1376 case 0xE31:
1377 case 0xE34:
1378 case 0xE35:
1379 case 0xE36:
1380 case 0xE37: return Thai_ABOVE1; break;
1381 case 0xE47:
1382 case 0xE4D: return Thai_ABOVE2; break;
1383 case 0xE48:
1384 case 0xE49:
1385 case 0xE4A:
1386 case 0xE4B: return Thai_ABOVE3; break;
1387 case 0xE4C:
1388 case 0xE4E: return Thai_ABOVE4; break;
1389 case 0xE38:
1390 case 0xE39: return Thai_BELOW1; break;
1391 case 0xE3A: return Thai_BELOW2; break;
1392 case 0xE33: return Thai_AM; break;
1393 default: return Thai_Norm;
1397 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1399 INT dirL;
1401 if (*pcGlyphs != cChars)
1403 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1404 return;
1407 if (!psa->fLogicalOrder && psa->fRTL)
1408 dirL = -1;
1409 else
1410 dirL = 1;
1412 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1415 static int combining_lexical_Lao(WCHAR c)
1417 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1419 switch(c)
1421 case 0xEB1:
1422 case 0xEB4:
1423 case 0xEB5:
1424 case 0xEB6:
1425 case 0xEB7:
1426 case 0xEBB:
1427 case 0xECD: return Lao_ABOVE1; break;
1428 case 0xEC8:
1429 case 0xEC9:
1430 case 0xECA:
1431 case 0xECB:
1432 case 0xECC: return Lao_ABOVE2; break;
1433 case 0xEBC: return Lao_BELOW1; break;
1434 case 0xEB8:
1435 case 0xEB9: return Lao_BELOW2; break;
1436 case 0xEB3: return Lao_AM; break;
1437 default: return Lao_Norm;
1441 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1443 INT dirL;
1445 if (*pcGlyphs != cChars)
1447 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1448 return;
1451 if (!psa->fLogicalOrder && psa->fRTL)
1452 dirL = -1;
1453 else
1454 dirL = 1;
1456 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1459 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1461 int i;
1463 /* Replace */
1464 pwOutChars[cWalk] = replacements[0];
1465 cWalk=cWalk+1;
1467 /* Insert */
1468 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1470 int j;
1471 for (j = *pcChars; j > cWalk; j--)
1472 pwOutChars[j] = pwOutChars[j-1];
1473 *pcChars= *pcChars+1;
1474 pwOutChars[cWalk] = replacements[i];
1475 cWalk = cWalk+1;
1479 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1481 int i;
1482 int cWalk;
1484 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1486 for (i = 0; vowels[i].base != 0x0; i++)
1488 if (pwOutChars[cWalk] == vowels[i].base)
1490 int o = 0;
1491 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1492 if (vowels[i].parts[1]) { cWalk++; o++; }
1493 if (vowels[i].parts[2]) { cWalk++; o++; }
1494 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1495 break;
1501 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1503 int i;
1504 int offset = 0;
1505 int cWalk;
1507 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1509 for (i = 0; consonants[i].output!= 0x0; i++)
1511 int j;
1512 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1513 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1514 break;
1516 if (consonants[i].parts[j]==0x0) /* matched all */
1518 int k;
1519 j--;
1520 pwOutChars[cWalk] = consonants[i].output;
1521 for(k = cWalk+1; k < *pcChars - j; k++)
1522 pwOutChars[k] = pwOutChars[k+j];
1523 *pcChars = *pcChars - j;
1524 for (k = j ; k > 0; k--)
1525 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1526 offset += j;
1527 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1528 pwLogClust[k]--;
1529 break;
1532 cWalk++;
1536 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1538 if (s->ralf >= 0)
1540 int j;
1541 WORD Ra = pwChar[s->start];
1542 WORD H = pwChar[s->start+1];
1544 TRACE("Doing reorder of Ra to %i\n",s->base);
1545 for (j = s->start; j < s->base-1; j++)
1546 pwChar[j] = pwChar[j+2];
1547 pwChar[s->base-1] = Ra;
1548 pwChar[s->base] = H;
1550 s->ralf = s->base-1;
1551 s->base -= 2;
1555 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1557 if (s->ralf >= 0)
1559 int j,loc;
1560 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1561 WORD Ra = pwChar[s->start];
1562 WORD H = pwChar[s->start+1];
1563 for (loc = s->end; loc > stop; loc--)
1564 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1565 break;
1567 TRACE("Doing reorder of Ra to %i\n",loc);
1568 for (j = s->start; j < loc-1; j++)
1569 pwChar[j] = pwChar[j+2];
1570 pwChar[loc-1] = Ra;
1571 pwChar[loc] = H;
1573 s->ralf = loc-1;
1574 s->base -= 2;
1575 if (s->blwf >= 0) s->blwf -= 2;
1576 if (s->pref >= 0) s->pref -= 2;
1580 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1582 if (s->ralf >= 0)
1584 int j;
1585 WORD Ra = pwChar[s->start];
1586 WORD H = pwChar[s->start+1];
1588 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1589 for (j = s->start; j < s->end-1; j++)
1590 pwChar[j] = pwChar[j+2];
1591 pwChar[s->end-1] = Ra;
1592 pwChar[s->end] = H;
1594 s->ralf = s->end-1;
1595 s->base -= 2;
1596 if (s->blwf >= 0) s->blwf -= 2;
1597 if (s->pref >= 0) s->pref -= 2;
1601 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1603 int i;
1605 /* reorder Matras */
1606 if (s->end > s->base)
1608 for (i = 1; i <= s->end-s->base; i++)
1610 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1612 int j;
1613 WCHAR c = pwChar[s->base+i];
1614 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1615 for (j = s->base+i; j > s->base; j--)
1616 pwChar[j] = pwChar[j-1];
1617 pwChar[s->base] = c;
1619 if (s->ralf >= s->base) s->ralf++;
1620 if (s->blwf >= s->base) s->blwf++;
1621 if (s->pref >= s->base) s->pref++;
1622 s->base ++;
1628 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1630 int i;
1632 /* reorder Matras */
1633 if (s->end > s->base)
1635 for (i = 1; i <= s->end-s->base; i++)
1637 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1639 int j;
1640 WCHAR c = pwChar[s->base+i];
1641 TRACE("Doing reorder of %x to %i\n",c,s->start);
1642 for (j = s->base+i; j > s->start; j--)
1643 pwChar[j] = pwChar[j-1];
1644 pwChar[s->start] = c;
1646 if (s->ralf >= 0) s->ralf++;
1647 if (s->blwf >= 0) s->blwf++;
1648 if (s->pref >= 0) s->pref++;
1649 s->base ++;
1655 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1657 if (s->blwf >= 0 && g->blwf > g->base)
1659 int j,loc;
1660 int g_offset;
1661 for (loc = s->end; loc > s->blwf; loc--)
1662 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1663 break;
1665 g_offset = (loc - s->blwf) - 1;
1667 if (loc != s->blwf)
1669 WORD blwf = glyphs[g->blwf];
1670 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1671 /* do not care about the pwChar array anymore, just the glyphs */
1672 for (j = 0; j < g_offset; j++)
1673 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1674 glyphs[g->blwf + g_offset] = blwf;
1679 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1681 int i;
1683 /* reorder previously moved Matras to correct position*/
1684 for (i = s->start; i < s->base; i++)
1686 if (lexical(pwChar[i]) == lex_Matra_pre)
1688 int j;
1689 int g_start = g->start + i - s->start;
1690 if (g_start < g->base -1 )
1692 WCHAR og = glyphs[g_start];
1693 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1694 for (j = g_start; j < g->base-1; j++)
1695 glyphs[j] = glyphs[j+1];
1696 glyphs[g->base-1] = og;
1702 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1704 if (s->pref >= 0 && g->pref > g->base)
1706 int j;
1707 WCHAR og = glyphs[g->pref];
1708 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1709 for (j = g->pref; j > g->base; j--)
1710 glyphs[j] = glyphs[j-1];
1711 glyphs[g->base] = og;
1715 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1717 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1718 if (s->start == s->base && s->base == s->end) return;
1719 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1721 Reorder_Ra_follows_base(pwChar, s, lexical);
1722 Reorder_Matra_precede_base(pwChar, s, lexical);
1725 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1727 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1728 if (s->start == s->base && s->base == s->end) return;
1729 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1731 Reorder_Ra_follows_matra(pwChar, s, lexical);
1732 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1735 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1737 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1738 if (s->start == s->base && s->base == s->end) return;
1739 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1741 Reorder_Ra_follows_base(pwChar, s, lexical);
1742 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1745 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1747 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1748 if (s->start == s->base && s->base == s->end) return;
1749 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1751 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1752 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1755 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1757 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1758 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1759 if (s->start == s->base && s->base == s->end) return;
1760 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1762 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1765 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1767 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1768 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1769 if (s->start == s->base && s->base == s->end) return;
1770 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1772 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1773 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1777 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1779 if (shift == 0)
1780 return;
1782 if (glyph_index->start > index)
1783 glyph_index->start += shift;
1784 if (glyph_index->base > index)
1785 glyph_index->base+= shift;
1786 if (glyph_index->end > index)
1787 glyph_index->end+= shift;
1788 if (glyph_index->ralf > index)
1789 glyph_index->ralf+= shift;
1790 if (glyph_index->blwf > index)
1791 glyph_index->blwf+= shift;
1792 if (glyph_index->pref > index)
1793 glyph_index->pref+= shift;
1796 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 )
1798 int index = glyph_index->start;
1800 if (!feature)
1801 return;
1803 while(index <= glyph_index->end)
1805 INT nextIndex;
1806 INT prevCount = *pcGlyphs;
1807 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1808 if (nextIndex > GSUB_E_NOGLYPH)
1810 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1811 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1812 index = nextIndex;
1814 else
1815 index++;
1819 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1821 int i = 0;
1822 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)))))
1823 i++;
1824 if (index + i <= end-1)
1825 return index + i;
1826 else
1827 return -1;
1830 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)
1832 INT index, nextIndex;
1833 INT count,g_offset;
1835 count = syllable->base - syllable->start;
1837 g_offset = 0;
1838 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1839 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1841 INT prevCount = *pcGlyphs;
1842 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1843 if (nextIndex > GSUB_E_NOGLYPH)
1845 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1846 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1847 g_offset += (*pcGlyphs - prevCount);
1850 index+=2;
1851 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1855 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)
1857 INT nextIndex;
1858 INT prevCount = *pcGlyphs;
1860 if (syllable->ralf >= 0)
1862 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1863 if (nextIndex > GSUB_E_NOGLYPH)
1865 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1866 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1871 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1873 int i = 0;
1874 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1875 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1876 is_consonant(lexical(pwChars[index+i+1])))))
1877 i++;
1878 if (index + i <= end-1)
1879 return index+i;
1880 else
1881 return -1;
1884 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)
1886 INT index, nextIndex;
1887 INT count, g_offset=0;
1888 INT ralf = syllable->ralf;
1890 count = syllable->end - syllable->base;
1892 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
1894 while (index >= 0)
1896 INT prevCount = *pcGlyphs;
1897 if (ralf >=0 && ralf < index)
1899 g_offset--;
1900 ralf = -1;
1903 if (!modern)
1905 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1906 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1907 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1910 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
1911 if (nextIndex > GSUB_E_NOGLYPH)
1913 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1914 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
1915 g_offset += (*pcGlyphs - prevCount);
1917 else if (!modern)
1919 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1920 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1921 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1924 index+=2;
1925 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
1929 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)
1931 int c;
1932 int overall_shift = 0;
1933 LoadedFeature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
1934 LoadedFeature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
1935 LoadedFeature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
1936 LoadedFeature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
1937 LoadedFeature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
1938 LoadedFeature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
1939 LoadedFeature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
1940 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
1941 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
1942 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
1943 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
1944 IndicSyllable glyph_indexs;
1946 for (c = 0; c < syllable_count; c++)
1948 int old_end;
1949 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
1950 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
1951 old_end = glyph_indexs.end;
1953 if (locl)
1955 TRACE("applying feature locl\n");
1956 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
1958 if (nukt)
1960 TRACE("applying feature nukt\n");
1961 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
1963 if (akhn)
1965 TRACE("applying feature akhn\n");
1966 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
1969 if (rphf)
1970 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
1971 if (rkrf)
1973 TRACE("applying feature rkrf\n");
1974 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
1976 if (pref)
1977 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
1978 if (blwf)
1980 if (!modern)
1981 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
1983 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
1986 if (half)
1987 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
1988 if (pstf)
1990 TRACE("applying feature pstf\n");
1991 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
1993 if (vatu)
1995 TRACE("applying feature vatu\n");
1996 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
1998 if (cjct)
2000 TRACE("applying feature cjct\n");
2001 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2004 if (second_reorder)
2005 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2007 overall_shift += glyph_indexs.end - old_end;
2011 static inline int unicode_lex(WCHAR c)
2013 int type;
2015 if (!c) return lex_Generic;
2016 if (c == 0x200D) return lex_ZWJ;
2017 if (c == 0x200C) return lex_ZWNJ;
2018 if (c == 0x00A0) return lex_NBSP;
2020 type = get_table_entry( indic_syllabic_table, c );
2022 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2024 switch( type )
2026 case 0x0d07: /* Unknown */
2027 case 0x0e07: /* Unknwon */
2028 default: return lex_Generic;
2029 case 0x0001:
2030 case 0x0002:
2031 case 0x0011:
2032 case 0x0012:
2033 case 0x0013:
2034 case 0x0014: return lex_Modifier;
2035 case 0x0003:
2036 case 0x0009:
2037 case 0x000a:
2038 case 0x000b:
2039 case 0x000d:
2040 case 0x000e:
2041 case 0x000f:
2042 case 0x0010: return lex_Consonant;
2043 case 0x0004: return lex_Nukta;
2044 case 0x0005: return lex_Halant;
2045 case 0x0006:
2046 case 0x0008: return lex_Vowel;
2047 case 0x0007:
2048 case 0x0107: return lex_Matra_post;
2049 case 0x0207:
2050 case 0x0307: return lex_Matra_pre;
2051 case 0x0807:
2052 case 0x0907:
2053 case 0x0a07:
2054 case 0x0b07:
2055 case 0x0c07:
2056 case 0x0407: return lex_Composed_Vowel;
2057 case 0x0507: return lex_Matra_above;
2058 case 0x0607: return lex_Matra_below;
2059 case 0x000c: return lex_Ra;
2063 static int sinhala_lex(WCHAR c)
2065 switch (c)
2067 case 0x0DDA:
2068 case 0x0DDD:
2069 case 0x0DDC:
2070 case 0x0DDE: return lex_Matra_post;
2071 default:
2072 return unicode_lex(c);
2076 static const VowelComponents Sinhala_vowels[] = {
2077 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2078 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2079 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2080 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2081 {0x0000, {0x0000,0x0000,0x0}}};
2083 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2085 int cCount = cChars;
2086 int i;
2087 WCHAR *input;
2088 IndicSyllable *syllables = NULL;
2089 int syllable_count = 0;
2091 if (*pcGlyphs != cChars)
2093 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2094 return;
2097 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2099 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2101 /* Step 1: Decompose multi part vowels */
2102 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2104 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2106 /* Step 2: Reorder within Syllables */
2107 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2108 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2110 /* Step 3: Strip dangling joiners */
2111 for (i = 0; i < cCount; i++)
2113 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2114 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2115 input[i] = 0x0020;
2118 /* Step 4: Base Form application to syllables */
2119 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2120 *pcGlyphs = cCount;
2121 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2123 HeapFree(GetProcessHeap(),0,input);
2124 HeapFree(GetProcessHeap(),0,syllables);
2127 static int devanagari_lex(WCHAR c)
2129 switch (c)
2131 case 0x0930: return lex_Ra;
2132 default:
2133 return unicode_lex(c);
2137 static const ConsonantComponents Devanagari_consonants[] ={
2138 {{0x0928, 0x093C, 0x00000}, 0x0929},
2139 {{0x0930, 0x093C, 0x00000}, 0x0931},
2140 {{0x0933, 0x093C, 0x00000}, 0x0934},
2141 {{0x0915, 0x093C, 0x00000}, 0x0958},
2142 {{0x0916, 0x093C, 0x00000}, 0x0959},
2143 {{0x0917, 0x093C, 0x00000}, 0x095A},
2144 {{0x091C, 0x093C, 0x00000}, 0x095B},
2145 {{0x0921, 0x093C, 0x00000}, 0x095C},
2146 {{0x0922, 0x093C, 0x00000}, 0x095D},
2147 {{0x092B, 0x093C, 0x00000}, 0x095E},
2148 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2150 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2152 int cCount = cChars;
2153 WCHAR *input;
2154 IndicSyllable *syllables = NULL;
2155 int syllable_count = 0;
2156 BOOL modern = get_GSUB_Indic2(psa, psc);
2158 if (*pcGlyphs != cChars)
2160 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2161 return;
2164 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2165 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2167 /* Step 1: Compose Consonant and Nukta */
2168 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2169 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2171 /* Step 2: Reorder within Syllables */
2172 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2173 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2174 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2175 *pcGlyphs = cCount;
2177 /* Step 3: Base Form application to syllables */
2178 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2180 HeapFree(GetProcessHeap(),0,input);
2181 HeapFree(GetProcessHeap(),0,syllables);
2184 static int bengali_lex(WCHAR c)
2186 switch (c)
2188 case 0x09B0: return lex_Ra;
2189 default:
2190 return unicode_lex(c);
2194 static const VowelComponents Bengali_vowels[] = {
2195 {0x09CB, {0x09C7,0x09BE,0x0000}},
2196 {0x09CC, {0x09C7,0x09D7,0x0000}},
2197 {0x0000, {0x0000,0x0000,0x0000}}};
2199 static const ConsonantComponents Bengali_consonants[] = {
2200 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2201 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2202 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2203 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2204 {{0x0000,0x0000,0x0000}, 0x0000}};
2206 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2208 int cCount = cChars;
2209 WCHAR *input;
2210 IndicSyllable *syllables = NULL;
2211 int syllable_count = 0;
2212 BOOL modern = get_GSUB_Indic2(psa, psc);
2214 if (*pcGlyphs != cChars)
2216 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2217 return;
2220 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2221 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2223 /* Step 1: Decompose Vowels and Compose Consonants */
2224 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2225 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2226 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2228 /* Step 2: Reorder within Syllables */
2229 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2230 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2231 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2232 *pcGlyphs = cCount;
2234 /* Step 3: Initial form is only applied to the beginning of words */
2235 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2237 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2239 int index = cCount;
2240 int gCount = 1;
2241 if (index > 0) index++;
2243 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2247 /* Step 4: Base Form application to syllables */
2248 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2250 HeapFree(GetProcessHeap(),0,input);
2251 HeapFree(GetProcessHeap(),0,syllables);
2254 static int gurmukhi_lex(WCHAR c)
2256 if (c == 0x0A71)
2257 return lex_Modifier;
2258 else
2259 return unicode_lex(c);
2262 static const ConsonantComponents Gurmukhi_consonants[] = {
2263 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2264 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2265 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2266 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2267 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2268 {{0x0000,0x0000,0x0000}, 0x0000}};
2270 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2272 int cCount = cChars;
2273 WCHAR *input;
2274 IndicSyllable *syllables = NULL;
2275 int syllable_count = 0;
2276 BOOL modern = get_GSUB_Indic2(psa, psc);
2278 if (*pcGlyphs != cChars)
2280 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2281 return;
2284 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2285 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2287 /* Step 1: Compose Consonants */
2288 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2289 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2291 /* Step 2: Reorder within Syllables */
2292 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2293 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2294 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2295 *pcGlyphs = cCount;
2297 /* Step 3: Base Form application to syllables */
2298 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2300 HeapFree(GetProcessHeap(),0,input);
2301 HeapFree(GetProcessHeap(),0,syllables);
2304 static int gujarati_lex(WCHAR c)
2306 switch (c)
2308 case 0x0AB0: return lex_Ra;
2309 default:
2310 return unicode_lex(c);
2314 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2316 int cCount = cChars;
2317 WCHAR *input;
2318 IndicSyllable *syllables = NULL;
2319 int syllable_count = 0;
2320 BOOL modern = get_GSUB_Indic2(psa, psc);
2322 if (*pcGlyphs != cChars)
2324 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2325 return;
2328 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2329 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2331 /* Step 1: Reorder within Syllables */
2332 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2333 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2334 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2335 *pcGlyphs = cCount;
2337 /* Step 2: Base Form application to syllables */
2338 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2340 HeapFree(GetProcessHeap(),0,input);
2341 HeapFree(GetProcessHeap(),0,syllables);
2344 static int oriya_lex(WCHAR c)
2346 switch (c)
2348 case 0x0B30: return lex_Ra;
2349 default:
2350 return unicode_lex(c);
2354 static const VowelComponents Oriya_vowels[] = {
2355 {0x0B48, {0x0B47,0x0B56,0x0000}},
2356 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2357 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2358 {0x0000, {0x0000,0x0000,0x0000}}};
2360 static const ConsonantComponents Oriya_consonants[] = {
2361 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2362 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2363 {{0x0000,0x0000,0x0000}, 0x0000}};
2365 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2367 int cCount = cChars;
2368 WCHAR *input;
2369 IndicSyllable *syllables = NULL;
2370 int syllable_count = 0;
2371 BOOL modern = get_GSUB_Indic2(psa, psc);
2373 if (*pcGlyphs != cChars)
2375 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2376 return;
2379 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2380 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2382 /* Step 1: Decompose Vowels and Compose Consonants */
2383 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2384 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2385 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2387 /* Step 2: Reorder within Syllables */
2388 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2389 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2390 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2391 *pcGlyphs = cCount;
2393 /* Step 3: Base Form application to syllables */
2394 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2396 HeapFree(GetProcessHeap(),0,input);
2397 HeapFree(GetProcessHeap(),0,syllables);
2400 static int tamil_lex(WCHAR c)
2402 return unicode_lex(c);
2405 static const VowelComponents Tamil_vowels[] = {
2406 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2407 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2408 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2409 {0x0000, {0x0000,0x0000,0x0000}}};
2411 static const ConsonantComponents Tamil_consonants[] = {
2412 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2413 {{0x0000,0x0000,0x0000}, 0x0000}};
2415 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2417 int cCount = cChars;
2418 WCHAR *input;
2419 IndicSyllable *syllables = NULL;
2420 int syllable_count = 0;
2421 BOOL modern = get_GSUB_Indic2(psa, psc);
2423 if (*pcGlyphs != cChars)
2425 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2426 return;
2429 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2430 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2432 /* Step 1: Decompose Vowels and Compose Consonants */
2433 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2434 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2435 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2437 /* Step 2: Reorder within Syllables */
2438 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2439 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2440 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2441 *pcGlyphs = cCount;
2443 /* Step 3: Base Form application to syllables */
2444 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2446 HeapFree(GetProcessHeap(),0,input);
2447 HeapFree(GetProcessHeap(),0,syllables);
2450 static int telugu_lex(WCHAR c)
2452 switch (c)
2454 case 0x0C43:
2455 case 0x0C44: return lex_Modifier;
2456 default:
2457 return unicode_lex(c);
2461 static const VowelComponents Telugu_vowels[] = {
2462 {0x0C48, {0x0C46,0x0C56,0x0000}},
2463 {0x0000, {0x0000,0x0000,0x0000}}};
2465 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2467 int cCount = cChars;
2468 WCHAR *input;
2469 IndicSyllable *syllables = NULL;
2470 int syllable_count = 0;
2471 BOOL modern = get_GSUB_Indic2(psa, psc);
2473 if (*pcGlyphs != cChars)
2475 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2476 return;
2479 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2480 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2482 /* Step 1: Decompose Vowels */
2483 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2484 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2486 /* Step 2: Reorder within Syllables */
2487 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2488 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2489 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2490 *pcGlyphs = cCount;
2492 /* Step 3: Base Form application to syllables */
2493 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2495 HeapFree(GetProcessHeap(),0,input);
2496 HeapFree(GetProcessHeap(),0,syllables);
2499 static int kannada_lex(WCHAR c)
2501 switch (c)
2503 case 0x0CB0: return lex_Ra;
2504 default:
2505 return unicode_lex(c);
2509 static const VowelComponents Kannada_vowels[] = {
2510 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2511 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2512 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2513 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2514 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2515 {0x0000, {0x0000,0x0000,0x0000}}};
2517 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2519 int cCount = cChars;
2520 WCHAR *input;
2521 IndicSyllable *syllables = NULL;
2522 int syllable_count = 0;
2523 BOOL modern = get_GSUB_Indic2(psa, psc);
2525 if (*pcGlyphs != cChars)
2527 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2528 return;
2531 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2532 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2534 /* Step 1: Decompose Vowels */
2535 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2536 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2538 /* Step 2: Reorder within Syllables */
2539 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2540 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2541 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2542 *pcGlyphs = cCount;
2544 /* Step 3: Base Form application to syllables */
2545 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2547 HeapFree(GetProcessHeap(),0,input);
2548 HeapFree(GetProcessHeap(),0,syllables);
2551 static int malayalam_lex(WCHAR c)
2553 return unicode_lex(c);
2556 static const VowelComponents Malayalam_vowels[] = {
2557 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2558 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2559 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2560 {0x0000, {0x0000,0x0000,0x0000}}};
2562 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2564 int cCount = cChars;
2565 WCHAR *input;
2566 IndicSyllable *syllables = NULL;
2567 int syllable_count = 0;
2568 BOOL modern = get_GSUB_Indic2(psa, psc);
2570 if (*pcGlyphs != cChars)
2572 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2573 return;
2576 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2577 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2579 /* Step 1: Decompose Vowels */
2580 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2581 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2583 /* Step 2: Reorder within Syllables */
2584 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2585 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2586 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2587 *pcGlyphs = cCount;
2589 /* Step 3: Base Form application to syllables */
2590 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2592 HeapFree(GetProcessHeap(),0,input);
2593 HeapFree(GetProcessHeap(),0,syllables);
2596 static int khmer_lex(WCHAR c)
2598 return unicode_lex(c);
2601 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2603 int cCount = cChars;
2604 WCHAR *input;
2605 IndicSyllable *syllables = NULL;
2606 int syllable_count = 0;
2608 if (*pcGlyphs != cChars)
2610 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2611 return;
2614 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2615 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2617 /* Step 1: Reorder within Syllables */
2618 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2619 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2620 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2621 *pcGlyphs = cCount;
2623 /* Step 2: Base Form application to syllables */
2624 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2626 HeapFree(GetProcessHeap(),0,input);
2627 HeapFree(GetProcessHeap(),0,syllables);
2630 static inline BOOL mongolian_wordbreak(WCHAR chr)
2632 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2635 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2637 INT *context_shape;
2638 INT dirL;
2639 int i;
2641 if (*pcGlyphs != cChars)
2643 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2644 return;
2647 if (!psa->fLogicalOrder && psa->fRTL)
2648 dirL = -1;
2649 else
2650 dirL = 1;
2652 if (!psc->GSUB_Table)
2653 psc->GSUB_Table = load_gsub_table(hdc);
2655 if (!psc->GSUB_Table)
2656 return;
2658 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2660 for (i = 0; i < cChars; i++)
2662 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2664 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2665 context_shape[i] = Xn;
2666 else
2667 context_shape[i] = Xl;
2669 else
2671 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2672 context_shape[i] = Xr;
2673 else
2674 context_shape[i] = Xm;
2678 /* Contextual Shaping */
2679 i = 0;
2680 while(i < *pcGlyphs)
2682 INT nextIndex;
2683 INT prevCount = *pcGlyphs;
2684 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2685 if (nextIndex > GSUB_E_NOGLYPH)
2687 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2688 i = nextIndex;
2690 else
2691 i++;
2694 HeapFree(GetProcessHeap(),0,context_shape);
2697 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)
2699 int i,k;
2701 for (i = 0; i < cGlyphs; i++)
2703 int char_index[20];
2704 int char_count = 0;
2706 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2707 if (k>=0)
2709 for (; k < cChars && pwLogClust[k] == i; k++)
2710 char_index[char_count++] = k;
2713 if (char_count == 0)
2714 continue;
2716 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2718 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2719 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2721 else
2722 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2725 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2726 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2729 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 )
2731 int i,k;
2732 int initGlyph, finaGlyph;
2733 INT dirR, dirL;
2734 BYTE *spaces;
2736 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2737 memset(spaces,0,cGlyphs);
2739 if (!psa->fLogicalOrder && psa->fRTL)
2741 initGlyph = cGlyphs-1;
2742 finaGlyph = 0;
2743 dirR = 1;
2744 dirL = -1;
2746 else
2748 initGlyph = 0;
2749 finaGlyph = cGlyphs-1;
2750 dirR = -1;
2751 dirL = 1;
2754 for (i = 0; i < cGlyphs; i++)
2756 for (k = 0; k < cChars; k++)
2757 if (pwLogClust[k] == i)
2759 if (pwcChars[k] == 0x0020)
2760 spaces[i] = 1;
2764 for (i = 0; i < cGlyphs; i++)
2766 int char_index[20];
2767 int char_count = 0;
2768 BOOL isInit, isFinal;
2770 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2771 if (k>=0)
2773 for (; k < cChars && pwLogClust[k] == i; k++)
2774 char_index[char_count++] = k;
2777 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2778 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2780 if (char_count == 0)
2781 continue;
2783 if (char_count == 1)
2785 if (pwcChars[char_index[0]] == 0x0020) /* space */
2787 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2788 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2790 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2791 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2792 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2794 if (!isInit && !isFinal)
2795 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2796 else if (isInit)
2797 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2798 else
2799 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2801 else if (!isInit)
2803 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2804 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2805 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2806 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2807 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2808 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2809 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2810 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2811 else
2812 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2814 else if (!isInit && !isFinal)
2815 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2816 else
2817 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2819 else if (char_count == 2)
2821 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2822 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2823 else if (!isInit)
2824 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2825 else
2826 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2828 else if (!isInit && !isFinal)
2829 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2830 else
2831 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2834 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2835 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2836 HeapFree(GetProcessHeap(),0,spaces);
2839 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 )
2841 int i;
2842 int finaGlyph;
2843 INT dirL;
2845 if (!psa->fLogicalOrder && psa->fRTL)
2847 finaGlyph = 0;
2848 dirL = -1;
2850 else
2852 finaGlyph = cGlyphs-1;
2853 dirL = 1;
2856 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2858 for (i = 0; i < cGlyphs; i++)
2860 int k;
2861 int char_index[20];
2862 int char_count = 0;
2864 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2865 if (k>=0)
2867 for (; k < cChars && pwLogClust[k] == i; k++)
2868 char_index[char_count++] = k;
2871 if (i == finaGlyph)
2872 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2873 else
2874 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2876 if (char_count == 0)
2877 continue;
2879 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2880 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2882 /* handle Thai SARA AM (U+0E33) differently than GDEF */
2883 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
2884 pGlyphProp[i].sva.fClusterStart = 0;
2887 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2889 /* Do not allow justification between marks and their base */
2890 for (i = 0; i < cGlyphs; i++)
2892 if (!pGlyphProp[i].sva.fClusterStart)
2893 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2897 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)
2899 int i,k;
2901 for (i = 0; i < cGlyphs; i++)
2903 int char_index[20];
2904 int char_count = 0;
2906 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2907 if (k>=0)
2909 for (; k < cChars && pwLogClust[k] == i; k++)
2910 char_index[char_count++] = k;
2913 if (char_count == 0)
2914 continue;
2916 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2918 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2919 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2921 else
2922 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2924 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2925 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2928 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)
2930 int i,k;
2932 for (i = 0; i < cGlyphs; i++)
2934 int char_index[20];
2935 int char_count = 0;
2937 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2938 if (k>=0)
2940 for (; k < cChars && pwLogClust[k] == i; k++)
2941 char_index[char_count++] = k;
2944 if (char_count == 0)
2945 continue;
2947 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2949 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2950 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2952 else
2953 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2955 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2956 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2958 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2959 for (i = 0; i < cGlyphs; i++)
2961 if (!pGlyphProp[i].sva.fClusterStart)
2963 pGlyphProp[i].sva.fDiacritic = 0;
2964 pGlyphProp[i].sva.fZeroWidth = 0;
2969 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)
2971 int i,k;
2973 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2974 for (i = 0; i < cGlyphs; i++)
2976 int char_index[20];
2977 int char_count = 0;
2979 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2980 if (k>=0)
2982 for (; k < cChars && pwLogClust[k] == i; k++)
2983 char_index[char_count++] = k;
2986 if (override_gsub)
2988 /* Most indic scripts do not set fDiacritic or fZeroWidth */
2989 pGlyphProp[i].sva.fDiacritic = FALSE;
2990 pGlyphProp[i].sva.fZeroWidth = FALSE;
2993 if (char_count == 0)
2994 continue;
2996 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2998 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2999 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3001 else
3002 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3004 pGlyphProp[i].sva.fClusterStart = 0;
3005 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3006 switch (lexical(pwcChars[char_index[k]]))
3008 case lex_Matra_pre:
3009 case lex_Matra_post:
3010 case lex_Matra_above:
3011 case lex_Matra_below:
3012 case lex_Modifier:
3013 case lex_Halant:
3014 break;
3015 case lex_ZWJ:
3016 case lex_ZWNJ:
3017 /* check for dangling joiners */
3018 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3019 pGlyphProp[i].sva.fClusterStart = 1;
3020 else
3021 k = char_count;
3022 break;
3023 default:
3024 pGlyphProp[i].sva.fClusterStart = 1;
3025 break;
3029 if (use_syllables)
3031 IndicSyllable *syllables = NULL;
3032 int syllable_count = 0;
3033 BOOL modern = get_GSUB_Indic2(psa, psc);
3035 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3037 for (i = 0; i < syllable_count; i++)
3039 int j;
3040 WORD g = pwLogClust[syllables[i].start];
3041 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3043 if (pwLogClust[j] != g)
3045 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3046 pwLogClust[j] = g;
3051 HeapFree(GetProcessHeap(), 0, syllables);
3054 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3057 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 )
3059 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3062 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 )
3064 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3067 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 )
3069 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3072 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 )
3074 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3077 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 )
3079 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3082 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 )
3084 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3087 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 )
3089 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3092 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 )
3094 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3097 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 )
3099 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3102 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 )
3104 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3107 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 )
3109 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3112 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)
3114 if (ShapingData[psa->eScript].charGlyphPropProc)
3115 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3116 else
3117 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3120 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3122 if (!psc->GSUB_Table)
3123 psc->GSUB_Table = load_gsub_table(hdc);
3125 if (ShapingData[psa->eScript].contextProc)
3126 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3129 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)
3131 int i;
3132 INT dirL;
3134 if (!rpRangeProperties)
3135 return;
3137 if (!psc->GSUB_Table)
3138 psc->GSUB_Table = load_gsub_table(hdc);
3140 if (!psc->GSUB_Table)
3141 return;
3143 if (!psa->fLogicalOrder && psa->fRTL)
3144 dirL = -1;
3145 else
3146 dirL = 1;
3148 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3150 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3151 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3155 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3157 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3158 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3160 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3163 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3165 LoadedFeature *feature;
3166 int i;
3168 if (!ShapingData[psa->eScript].requiredFeatures)
3169 return S_OK;
3171 if (!psc->GSUB_Table)
3172 psc->GSUB_Table = load_gsub_table(hdc);
3174 /* we need to have at least one of the required features */
3175 i = 0;
3176 while (ShapingData[psa->eScript].requiredFeatures[i])
3178 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3179 if (feature)
3180 return S_OK;
3181 i++;
3184 return USP_E_SCRIPT_NOT_IN_FONT;
3187 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3188 SCRIPT_ANALYSIS *psa, int cMaxTags,
3189 OPENTYPE_TAG *pScriptTags, int *pcTags)
3191 HRESULT hr;
3192 OPENTYPE_TAG searching = 0x00000000;
3194 if (!psc->GSUB_Table)
3195 psc->GSUB_Table = load_gsub_table(hdc);
3197 if (psa && scriptInformation[psa->eScript].scriptTag)
3198 searching = scriptInformation[psa->eScript].scriptTag;
3200 hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL);
3201 if (FAILED(hr))
3202 *pcTags = 0;
3203 return hr;
3206 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3207 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3208 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3209 int *pcTags)
3211 HRESULT hr;
3212 OPENTYPE_TAG searching = 0x00000000;
3213 BOOL fellback = FALSE;
3215 if (!psc->GSUB_Table)
3216 psc->GSUB_Table = load_gsub_table(hdc);
3218 if (psa && psc->userLang != 0)
3219 searching = psc->userLang;
3221 hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL);
3222 if (FAILED(hr))
3224 fellback = TRUE;
3225 hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL);
3228 if (FAILED(hr) || fellback)
3229 *pcTags = 0;
3230 if (SUCCEEDED(hr) && fellback && psa)
3231 hr = E_INVALIDARG;
3232 return hr;
3235 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3236 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3237 OPENTYPE_TAG tagLangSys, int cMaxTags,
3238 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3240 HRESULT hr;
3241 BOOL filter = FALSE;
3243 if (!psc->GSUB_Table)
3244 psc->GSUB_Table = load_gsub_table(hdc);
3246 if (psa && scriptInformation[psa->eScript].scriptTag)
3248 FIXME("Filtering not implemented\n");
3249 filter = TRUE;
3252 hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL);
3254 if (FAILED(hr))
3255 *pcTags = 0;
3256 return hr;