usp10: Change OpenType_GSUB_GetFontScriptTags to OpenType_GetFontScriptTags and load...
[wine/multimedia.git] / dlls / usp10 / shape.c
blobb7d282241c87454091591199ed3860ec20f7b6a5
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_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
78 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 );
79 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 );
80 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 );
81 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 );
82 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 );
84 extern const unsigned short indic_syllabic_table[];
85 extern const unsigned short wine_shaping_table[];
86 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
88 enum joining_types {
89 jtU,
90 jtT,
91 jtR,
92 jtL,
93 jtD,
94 jtC
97 enum joined_forms {
98 Xn=0,
99 Xr,
102 /* Syriac Alaph */
103 Afj,
104 Afn,
108 typedef struct tagVowelComponents
110 WCHAR base;
111 WCHAR parts[3];
112 } VowelComponents;
114 typedef struct tagConsonantComponents
116 WCHAR parts[3];
117 WCHAR output;
118 } ConsonantComponents;
120 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
122 typedef int (*combining_lexical_function)(WCHAR c);
124 /* the orders of joined_forms and contextual_features need to line up */
125 static const char* contextual_features[] =
127 "isol",
128 "fina",
129 "init",
130 "medi",
131 /* Syriac Alaph */
132 "med2",
133 "fin2",
134 "fin3"
137 static OPENTYPE_FEATURE_RECORD standard_features[] =
139 { MS_MAKE_TAG('c','c','m','p'), 1},
140 { MS_MAKE_TAG('l','o','c','l'), 1},
143 static OPENTYPE_FEATURE_RECORD latin_features[] =
145 { MS_MAKE_TAG('l','i','g','a'), 1},
146 { MS_MAKE_TAG('c','l','i','g'), 1},
149 static OPENTYPE_FEATURE_RECORD arabic_features[] =
151 { MS_MAKE_TAG('r','l','i','g'), 1},
152 { MS_MAKE_TAG('c','a','l','t'), 1},
153 { MS_MAKE_TAG('l','i','g','a'), 1},
154 { MS_MAKE_TAG('d','l','i','g'), 1},
155 { MS_MAKE_TAG('c','s','w','h'), 1},
156 { MS_MAKE_TAG('m','s','e','t'), 1},
159 static const char* required_arabic_features[] =
161 "fina",
162 "init",
163 "medi",
164 "rlig",
165 NULL
168 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
170 { MS_MAKE_TAG('d','l','i','g'), 0},
173 static OPENTYPE_FEATURE_RECORD syriac_features[] =
175 { MS_MAKE_TAG('r','l','i','g'), 1},
176 { MS_MAKE_TAG('c','a','l','t'), 1},
177 { MS_MAKE_TAG('l','i','g','a'), 1},
178 { MS_MAKE_TAG('d','l','i','g'), 1},
181 static const char* required_syriac_features[] =
183 "fina",
184 "fin2",
185 "fin3",
186 "init",
187 "medi",
188 "med2",
189 "rlig",
190 NULL
193 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
195 /* Presentation forms */
196 { MS_MAKE_TAG('b','l','w','s'), 1},
197 { MS_MAKE_TAG('a','b','v','s'), 1},
198 { MS_MAKE_TAG('p','s','t','s'), 1},
201 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
203 { MS_MAKE_TAG('a','b','v','s'), 1},
204 { MS_MAKE_TAG('b','l','w','s'), 1},
207 static OPENTYPE_FEATURE_RECORD phags_features[] =
209 { MS_MAKE_TAG('a','b','v','s'), 1},
210 { MS_MAKE_TAG('b','l','w','s'), 1},
211 { MS_MAKE_TAG('c','a','l','t'), 1},
214 static OPENTYPE_FEATURE_RECORD thai_features[] =
216 { MS_MAKE_TAG('c','c','m','p'), 1},
219 static const char* required_lao_features[] =
221 "ccmp",
222 NULL
225 static const char* required_devanagari_features[] =
227 "nukt",
228 "akhn",
229 "rphf",
230 "blwf",
231 "half",
232 "vatu",
233 "pres",
234 "abvs",
235 "blws",
236 "psts",
237 "haln",
238 NULL
241 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
243 { MS_MAKE_TAG('p','r','e','s'), 1},
244 { MS_MAKE_TAG('a','b','v','s'), 1},
245 { MS_MAKE_TAG('b','l','w','s'), 1},
246 { MS_MAKE_TAG('p','s','t','s'), 1},
247 { MS_MAKE_TAG('h','a','l','n'), 1},
248 { MS_MAKE_TAG('c','a','l','t'), 1},
251 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
253 { MS_MAKE_TAG('l','i','g','a'), 1},
254 { MS_MAKE_TAG('c','l','i','g'), 1},
257 static const char* required_bengali_features[] =
259 "nukt",
260 "akhn",
261 "rphf",
262 "blwf",
263 "half",
264 "vatu",
265 "pstf",
266 "init",
267 "abvs",
268 "blws",
269 "psts",
270 "haln",
271 NULL
274 static const char* required_gurmukhi_features[] =
276 "nukt",
277 "akhn",
278 "rphf",
279 "blwf",
280 "half",
281 "pstf",
282 "vatu",
283 "cjct",
284 "pres",
285 "abvs",
286 "blws",
287 "psts",
288 "haln",
289 "calt",
290 NULL
293 static const char* required_oriya_features[] =
295 "nukt",
296 "akhn",
297 "rphf",
298 "blwf",
299 "pstf",
300 "cjct",
301 "pres",
302 "abvs",
303 "blws",
304 "psts",
305 "haln",
306 "calt",
307 NULL
310 static const char* required_tamil_features[] =
312 "nukt",
313 "akhn",
314 "rphf",
315 "pref",
316 "half",
317 "pres",
318 "abvs",
319 "blws",
320 "psts",
321 "haln",
322 "calt",
323 NULL
326 static const char* required_telugu_features[] =
328 "nukt",
329 "akhn",
330 "rphf",
331 "pref",
332 "half",
333 "pstf",
334 "cjct",
335 "pres",
336 "abvs",
337 "blws",
338 "psts",
339 "haln",
340 "calt",
341 NULL
344 static OPENTYPE_FEATURE_RECORD khmer_features[] =
346 { MS_MAKE_TAG('p','r','e','s'), 1},
347 { MS_MAKE_TAG('b','l','w','s'), 1},
348 { MS_MAKE_TAG('a','b','v','s'), 1},
349 { MS_MAKE_TAG('p','s','t','s'), 1},
350 { MS_MAKE_TAG('c','l','i','g'), 1},
353 static const char* required_khmer_features[] =
355 "pref",
356 "blwf",
357 "abvf",
358 "pstf",
359 "pres",
360 "blws",
361 "abvs",
362 "psts",
363 "clig",
364 NULL
367 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
369 { MS_MAKE_TAG('c','c','m','p'), 1},
370 { MS_MAKE_TAG('l','o','c','l'), 1},
371 { MS_MAKE_TAG('c','a','l','t'), 1},
372 { MS_MAKE_TAG('l','i','g','a'), 1},
375 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
377 { MS_MAKE_TAG('c','c','m','p'), 1},
378 { MS_MAKE_TAG('l','o','c','l'), 1},
379 { MS_MAKE_TAG('c','a','l','t'), 1},
380 { MS_MAKE_TAG('r','l','i','g'), 1},
383 typedef struct ScriptShapeDataTag {
384 TEXTRANGE_PROPERTIES defaultTextRange;
385 const char** requiredFeatures;
386 OPENTYPE_TAG newOtTag;
387 ContextualShapingProc contextProc;
388 ShapeCharGlyphPropProc charGlyphPropProc;
389 } ScriptShapeData;
391 /* in order of scripts */
392 static const ScriptShapeData ShapingData[] =
394 {{ standard_features, 2}, NULL, 0, NULL, NULL},
395 {{ latin_features, 2}, NULL, 0, NULL, NULL},
396 {{ latin_features, 2}, NULL, 0, NULL, NULL},
397 {{ latin_features, 2}, NULL, 0, NULL, NULL},
398 {{ standard_features, 2}, NULL, 0, NULL, NULL},
399 {{ latin_features, 2}, NULL, 0, NULL, NULL},
400 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
401 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
402 {{ hebrew_features, 1}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
403 {{ syriac_features, 4}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
404 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
405 {{ NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
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 {{ standard_features, 2}, NULL, 0, NULL, NULL},
410 {{ sinhala_features, 3}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
411 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
412 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
413 {{ phags_features, 3}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
414 {{ thai_features, 1}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
415 {{ thai_features, 1}, NULL, 0, ContextualShape_Thai, NULL},
416 {{ thai_features, 1}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
417 {{ thai_features, 1}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
418 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
419 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
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, NULL},
422 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
423 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
424 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
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, NULL},
427 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
428 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
429 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
430 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
431 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
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('t','e','l','2'), ContextualShape_Telugu, NULL},
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('k','n','d','2'), ContextualShape_Kannada, NULL},
436 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
437 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
438 {{ standard_features, 2}, NULL, 0, NULL, NULL},
439 {{ latin_features, 2}, NULL, 0, NULL, NULL},
440 {{ standard_features, 2}, NULL, 0, NULL, NULL},
441 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
442 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
443 {{ standard_features, 2}, NULL, 0, NULL, NULL},
444 {{ standard_features, 2}, NULL, 0, NULL, NULL},
445 {{ standard_features, 2}, NULL, 0, NULL, NULL},
446 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
447 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
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 {{ NULL, 0}, NULL, 0, NULL, NULL},
454 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
455 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
456 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
457 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, 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 {{ NULL, 0}, NULL, 0, NULL, NULL},
473 {{ hebrew_features, 1}, NULL, 0, ContextualShape_Hebrew, NULL},
474 {{ latin_features, 2}, NULL, 0, NULL, NULL},
475 {{ thai_features, 1}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
478 extern scriptData scriptInformation[];
480 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
482 int i;
483 int out_index = GSUB_E_NOGLYPH;
485 TRACE("%i lookups\n", feature->lookup_count);
486 for (i = 0; i < feature->lookup_count; i++)
488 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
489 if (out_index != GSUB_E_NOGLYPH)
490 break;
492 if (out_index == GSUB_E_NOGLYPH)
493 TRACE("lookups found no glyphs\n");
494 else
496 int out2;
497 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
498 if (out2!=GSUB_E_NOGLYPH)
499 out_index = out2;
501 return out_index;
504 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
506 UINT charset;
508 if (psc->userScript != 0)
510 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
511 return ShapingData[psa->eScript].newOtTag;
512 else
513 return psc->userScript;
516 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
517 return ShapingData[psa->eScript].newOtTag;
519 if (scriptInformation[psa->eScript].scriptTag)
520 return scriptInformation[psa->eScript].scriptTag;
523 * fall back to the font charset
525 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
526 switch (charset)
528 case ANSI_CHARSET:
529 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
530 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
531 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
532 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
533 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
534 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
535 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
536 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
537 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
538 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
539 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
540 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
541 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
542 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
543 default: return MS_MAKE_TAG('l','a','t','n');
547 static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
549 LoadedFeature *feature = NULL;
551 if (psc->GSUB_Table)
553 int attempt = 2;
554 OPENTYPE_TAG tags;
555 OPENTYPE_TAG language;
556 OPENTYPE_TAG script;
557 int cTags;
561 script = get_opentype_script(hdc,psa,psc,(attempt==2));
562 if (psc->userLang != 0)
563 language = psc->userLang;
564 else
565 language = MS_MAKE_TAG('d','f','l','t');
566 attempt--;
568 OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
570 } while(attempt && !feature);
572 /* try in the default (latin) table */
573 if (!feature)
574 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);
577 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
578 return feature;
581 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)
583 LoadedFeature *feature;
585 feature = load_GSUB_feature(hdc, psa, psc, feat);
586 if (!feature)
587 return GSUB_E_NOFEATURE;
589 TRACE("applying feature %s\n",feat);
590 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
593 static VOID *load_gsub_table(HDC hdc)
595 VOID* GSUB_Table = NULL;
596 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
597 if (length != GDI_ERROR)
599 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
600 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
601 TRACE("Loaded GSUB table of %i bytes\n",length);
603 return GSUB_Table;
606 static VOID *load_gpos_table(HDC hdc)
608 VOID* GPOS_Table = NULL;
609 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
610 if (length != GDI_ERROR)
612 GPOS_Table = HeapAlloc(GetProcessHeap(),0,length);
613 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
614 TRACE("Loaded GPOS table of %i bytes\n",length);
616 return GPOS_Table;
619 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
621 if (!psc->GSUB_Table)
622 psc->GSUB_Table = load_gsub_table(hdc);
623 if (!psc->GPOS_Table)
624 psc->GPOS_Table = load_gpos_table(hdc);
627 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)
629 WORD *glyphs;
630 INT glyph_count = count;
631 INT rc;
633 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
634 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
635 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
636 if (rc > GSUB_E_NOGLYPH)
637 rc = count - glyph_count;
638 else
639 rc = 0;
641 HeapFree(GetProcessHeap(),0,glyphs);
642 return rc;
645 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
647 int i;
649 for (i = 0; i < cGlyphs; i++)
651 if (!pGlyphProp[i].sva.fClusterStart)
653 int j;
654 for (j = 0; j < cChars; j++)
656 if (pwLogClust[j] == i)
658 int k = j;
659 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
660 k-=1;
661 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
662 pwLogClust[j] = pwLogClust[k];
669 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
671 if (changeCount == 0)
672 return;
673 else
675 int i;
676 int target_glyph = nextIndex - write_dir;
677 int seeking_glyph;
678 int target_index = -1;
679 int replacing_glyph = -1;
680 int changed = 0;
681 int top_logclust = 0;
683 if (changeCount > 0)
685 if (write_dir > 0)
686 target_glyph = nextIndex - changeCount;
687 else
688 target_glyph = nextIndex + (changeCount + 1);
691 seeking_glyph = target_glyph;
692 for (i = 0; i < chars; i++)
693 if (pwLogClust[i] > top_logclust)
694 top_logclust = pwLogClust[i];
696 do {
697 if (write_dir > 0)
698 for (i = 0; i < chars; i++)
700 if (pwLogClust[i] == seeking_glyph)
702 target_index = i;
703 break;
706 else
707 for (i = chars - 1; i >= 0; i--)
709 if (pwLogClust[i] == seeking_glyph)
711 target_index = i;
712 break;
715 if (target_index == -1)
716 seeking_glyph ++;
718 while (target_index == -1 && seeking_glyph <= top_logclust);
720 if (target_index == -1)
722 ERR("Unable to find target glyph\n");
723 return;
726 if (changeCount < 0)
728 /* merge glyphs */
729 for(i = target_index; i < chars && i >= 0; i+=write_dir)
731 if (pwLogClust[i] == target_glyph)
732 continue;
733 if(pwLogClust[i] == replacing_glyph)
734 pwLogClust[i] = target_glyph;
735 else
737 changed--;
738 if (changed >= changeCount)
740 replacing_glyph = pwLogClust[i];
741 pwLogClust[i] = target_glyph;
743 else
744 break;
748 /* renumber trailing indexes*/
749 for(i = target_index; i < chars && i >= 0; i+=write_dir)
751 if (pwLogClust[i] != target_glyph)
752 pwLogClust[i] += changeCount;
755 else
757 for(i = target_index; i < chars && i >= 0; i+=write_dir)
758 pwLogClust[i] += changeCount;
763 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 )
765 if (psc->GSUB_Table)
767 LoadedFeature *feature;
768 int lookup_index;
770 feature = load_GSUB_feature(hdc, psa, psc, feat);
771 if (!feature)
772 return GSUB_E_NOFEATURE;
774 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
775 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
777 int i;
779 if (write_dir > 0)
780 i = 0;
781 else
782 i = *pcGlyphs-1;
783 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
784 while(i < *pcGlyphs && i >= 0)
786 INT nextIndex;
787 INT prevCount = *pcGlyphs;
789 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
790 if (*pcGlyphs != prevCount)
792 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
793 i = nextIndex;
795 else
796 i+=write_dir;
799 return *pcGlyphs;
801 return GSUB_E_NOFEATURE;
804 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
806 OPENTYPE_TAG tag;
807 HRESULT hr;
808 int count = 0;
810 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
812 return(SUCCEEDED(hr));
815 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
817 int i;
818 for (i = *pcGlyphs; i>=index; i--)
819 pwGlyphs[i+1] = pwGlyphs[i];
820 pwGlyphs[index] = glyph;
821 *pcGlyphs = *pcGlyphs+1;
822 if (write_dir < 0)
823 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
824 else
825 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
828 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)
830 CHAR *context_type;
831 int i,g;
832 WCHAR invalid = 0x25cc;
833 WORD invalid_glyph;
835 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
837 /* Mark invalid combinations */
838 for (i = 0; i < cChars; i++)
839 context_type[i] = lex(pwcChars[i]);
841 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
842 for (i = 1, g=1; i < cChars; i++, g++)
844 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
846 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
847 g++;
851 HeapFree(GetProcessHeap(),0,context_type);
854 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
856 if (i + delta < 0)
857 return 0;
858 if ( i+ delta >= cchLen)
859 return 0;
861 i += delta;
863 return chars[i];
866 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
868 if (i + delta < 0)
870 if (psa->fLinkBefore)
871 return jtR;
872 else
873 return jtU;
875 if ( i+ delta >= cchLen)
877 if (psa->fLinkAfter)
878 return jtL;
879 else
880 return jtU;
883 i += delta;
885 if (context_type[i] == jtT)
886 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
887 else
888 return context_type[i];
891 static inline BOOL right_join_causing(CHAR joining_type)
893 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
896 static inline BOOL left_join_causing(CHAR joining_type)
898 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
901 static inline BOOL word_break_causing(WCHAR chr)
903 /* we are working within a string of characters already guareented to
904 be within one script, Syriac, so we do not worry about any character
905 other than the space character outside of that range */
906 return (chr == 0 || chr == 0x20 );
909 static int combining_lexical_Arabic(WCHAR c)
911 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
913 switch(c)
915 case 0x064B:
916 case 0x064C:
917 case 0x064E:
918 case 0x064F:
919 case 0x0652:
920 case 0x0657:
921 case 0x0658:
922 case 0x06E1: return Arab_DIAC1;
923 case 0x064D:
924 case 0x0650:
925 case 0x0656: return Arab_DIAC2;
926 case 0x0651: return Arab_DIAC3;
927 case 0x0610:
928 case 0x0611:
929 case 0x0612:
930 case 0x0613:
931 case 0x0614:
932 case 0x0659:
933 case 0x06D6:
934 case 0x06DC:
935 case 0x06DF:
936 case 0x06E0:
937 case 0x06E2:
938 case 0x06E4:
939 case 0x06E7:
940 case 0x06E8:
941 case 0x06EB:
942 case 0x06EC: return Arab_DIAC4;
943 case 0x06E3:
944 case 0x06EA:
945 case 0x06ED: return Arab_DIAC5;
946 case 0x0670: return Arab_DIAC6;
947 case 0x0653: return Arab_DIAC7;
948 case 0x0655:
949 case 0x0654: return Arab_DIAC8;
950 default: return Arab_Norm;
955 * ContextualShape_Arabic
957 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
959 CHAR *context_type;
960 INT *context_shape;
961 INT dirR, dirL;
962 int i;
964 if (*pcGlyphs != cChars)
966 ERR("Number of Glyphs and Chars need to match at the beginning\n");
967 return;
970 if (!psa->fLogicalOrder && psa->fRTL)
972 dirR = 1;
973 dirL = -1;
975 else
977 dirR = -1;
978 dirL = 1;
981 load_ot_tables(hdc, psc);
983 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
984 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
986 for (i = 0; i < cChars; i++)
987 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
989 for (i = 0; i < cChars; i++)
991 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
992 context_shape[i] = Xr;
993 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
994 context_shape[i] = Xl;
995 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)))
996 context_shape[i] = Xm;
997 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
998 context_shape[i] = Xr;
999 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1000 context_shape[i] = Xl;
1001 else
1002 context_shape[i] = Xn;
1005 /* Contextual Shaping */
1006 i = 0;
1007 while(i < *pcGlyphs)
1009 BOOL shaped = FALSE;
1011 if (psc->GSUB_Table)
1013 INT nextIndex;
1014 INT prevCount = *pcGlyphs;
1015 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1016 if (nextIndex > GSUB_E_NOGLYPH)
1018 i = nextIndex;
1019 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1021 shaped = (nextIndex > GSUB_E_NOGLYPH);
1024 if (!shaped)
1026 if (context_shape[i] == Xn)
1028 WORD newGlyph = pwOutGlyphs[i];
1029 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1031 /* fall back to presentation form B */
1032 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1033 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1034 pwOutGlyphs[i] = newGlyph;
1037 i++;
1041 HeapFree(GetProcessHeap(),0,context_shape);
1042 HeapFree(GetProcessHeap(),0,context_type);
1044 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1047 static int combining_lexical_Hebrew(WCHAR c)
1049 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};
1051 switch(c)
1053 case 0x05B0:
1054 case 0x05B1:
1055 case 0x05B2:
1056 case 0x05B3:
1057 case 0x05B4:
1058 case 0x05B5:
1059 case 0x05B6:
1060 case 0x05BB: return Hebr_DIAC;
1061 case 0x0599:
1062 case 0x05A1:
1063 case 0x05A9:
1064 case 0x05AE: return Hebr_CANT1;
1065 case 0x0597:
1066 case 0x05A8:
1067 case 0x05AC: return Hebr_CANT2;
1068 case 0x0592:
1069 case 0x0593:
1070 case 0x0594:
1071 case 0x0595:
1072 case 0x05A7:
1073 case 0x05AB: return Hebr_CANT3;
1074 case 0x0598:
1075 case 0x059C:
1076 case 0x059E:
1077 case 0x059F: return Hebr_CANT4;
1078 case 0x059D:
1079 case 0x05A0: return Hebr_CANT5;
1080 case 0x059B:
1081 case 0x05A5: return Hebr_CANT6;
1082 case 0x0591:
1083 case 0x05A3:
1084 case 0x05A6: return Hebr_CANT7;
1085 case 0x0596:
1086 case 0x05A4:
1087 case 0x05AA: return Hebr_CANT8;
1088 case 0x059A:
1089 case 0x05AD: return Hebr_CANT9;
1090 case 0x05AF: return Hebr_CANT10;
1091 case 0x05BC: return Hebr_DAGESH;
1092 case 0x05C4: return Hebr_DOTABV;
1093 case 0x05B9: return Hebr_HOLAM;
1094 case 0x05BD: return Hebr_METEG;
1095 case 0x05B7: return Hebr_PATAH;
1096 case 0x05B8: return Hebr_QAMATS;
1097 case 0x05BF: return Hebr_RAFE;
1098 case 0x05C1:
1099 case 0x05C2: return Hebr_SHINSIN;
1100 default: return Hebr_Norm;
1104 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1106 INT dirL;
1108 if (*pcGlyphs != cChars)
1110 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1111 return;
1114 if (!psa->fLogicalOrder && psa->fRTL)
1115 dirL = -1;
1116 else
1117 dirL = 1;
1119 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1123 * ContextualShape_Syriac
1126 static int combining_lexical_Syriac(WCHAR c)
1128 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};
1130 switch(c)
1132 case 0x730:
1133 case 0x733:
1134 case 0x736:
1135 case 0x73A:
1136 case 0x73D: return Syriac_DIAC1;
1137 case 0x731:
1138 case 0x734:
1139 case 0x737:
1140 case 0x73B:
1141 case 0x73E: return Syriac_DIAC2;
1142 case 0x740:
1143 case 0x749:
1144 case 0x74A: return Syriac_DIAC3;
1145 case 0x732:
1146 case 0x735:
1147 case 0x73F: return Syriac_DIAC4;
1148 case 0x738:
1149 case 0x739:
1150 case 0x73C: return Syriac_DIAC5;
1151 case 0x741:
1152 case 0x30A: return Syriac_DIAC6;
1153 case 0x742:
1154 case 0x325: return Syriac_DIAC7;
1155 case 0x747:
1156 case 0x303: return Syriac_DIAC8;
1157 case 0x748:
1158 case 0x32D:
1159 case 0x32E:
1160 case 0x330:
1161 case 0x331: return Syriac_DIAC9;
1162 case 0x308: return Syriac_DIAC10;
1163 case 0x304: return Syriac_DIAC11;
1164 case 0x307: return Syriac_DIAC12;
1165 case 0x323: return Syriac_DIAC13;
1166 case 0x743: return Syriac_DIAC14;
1167 case 0x744: return Syriac_DIAC15;
1168 case 0x745: return Syriac_DIAC16;
1169 case 0x746: return Syriac_DIAC17;
1170 default: return Syriac_Norm;
1174 #define ALAPH 0x710
1175 #define DALATH 0x715
1176 #define RISH 0x72A
1178 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1180 CHAR *context_type;
1181 INT *context_shape;
1182 INT dirR, dirL;
1183 int i;
1185 if (*pcGlyphs != cChars)
1187 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1188 return;
1191 if (!psa->fLogicalOrder && psa->fRTL)
1193 dirR = 1;
1194 dirL = -1;
1196 else
1198 dirR = -1;
1199 dirL = 1;
1202 load_ot_tables(hdc, psc);
1204 if (!psc->GSUB_Table)
1205 return;
1207 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1208 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1210 for (i = 0; i < cChars; i++)
1211 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1213 for (i = 0; i < cChars; i++)
1215 if (pwcChars[i] == ALAPH)
1217 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1219 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1220 context_shape[i] = Afj;
1221 else if ( rchar != DALATH && rchar != RISH &&
1222 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1223 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1224 context_shape[i] = Afn;
1225 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1226 context_shape[i] = Afx;
1227 else
1228 context_shape[i] = Xn;
1230 else if (context_type[i] == jtR &&
1231 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1232 context_shape[i] = Xr;
1233 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1234 context_shape[i] = Xl;
1235 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)))
1236 context_shape[i] = Xm;
1237 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1238 context_shape[i] = Xr;
1239 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1240 context_shape[i] = Xl;
1241 else
1242 context_shape[i] = Xn;
1245 /* Contextual Shaping */
1246 i = 0;
1247 while(i < *pcGlyphs)
1249 INT nextIndex;
1250 INT prevCount = *pcGlyphs;
1251 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1252 if (nextIndex > GSUB_E_NOGLYPH)
1254 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1255 i = nextIndex;
1257 else
1258 i++;
1261 HeapFree(GetProcessHeap(),0,context_shape);
1262 HeapFree(GetProcessHeap(),0,context_type);
1264 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1267 static int combining_lexical_Thaana(WCHAR c)
1269 enum {Thaana_Norm=0, Thaana_FILI};
1271 switch(c)
1273 case 0x7A6:
1274 case 0x7A7:
1275 case 0x7A8:
1276 case 0x7A9:
1277 case 0x7AA:
1278 case 0x7AB:
1279 case 0x7AC:
1280 case 0x7AD:
1281 case 0x7AE:
1282 case 0x7AF: return Thaana_FILI;
1283 default: return Thaana_Norm;
1287 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1289 INT dirL;
1291 if (*pcGlyphs != cChars)
1293 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1294 return;
1297 if (!psa->fLogicalOrder && psa->fRTL)
1298 dirL = -1;
1299 else
1300 dirL = 1;
1302 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1306 * ContextualShape_Phags_pa
1309 #define phags_pa_CANDRABINDU 0xA873
1310 #define phags_pa_START 0xA840
1311 #define phags_pa_END 0xA87F
1313 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1315 INT *context_shape;
1316 INT dirR, dirL;
1317 int i;
1319 if (*pcGlyphs != cChars)
1321 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1322 return;
1325 if (!psa->fLogicalOrder && psa->fRTL)
1327 dirR = 1;
1328 dirL = -1;
1330 else
1332 dirR = -1;
1333 dirL = 1;
1336 load_ot_tables(hdc, psc);
1338 if (!psc->GSUB_Table)
1339 return;
1341 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1343 for (i = 0; i < cChars; i++)
1345 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1347 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1348 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1349 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1350 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1352 if (jrchar && jlchar)
1353 context_shape[i] = Xm;
1354 else if (jrchar)
1355 context_shape[i] = Xr;
1356 else if (jlchar)
1357 context_shape[i] = Xl;
1358 else
1359 context_shape[i] = Xn;
1361 else
1362 context_shape[i] = -1;
1365 /* Contextual Shaping */
1366 i = 0;
1367 while(i < *pcGlyphs)
1369 if (context_shape[i] >= 0)
1371 INT nextIndex;
1372 INT prevCount = *pcGlyphs;
1373 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1374 if (nextIndex > GSUB_E_NOGLYPH)
1376 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1377 i = nextIndex;
1379 else
1380 i++;
1382 else
1383 i++;
1386 HeapFree(GetProcessHeap(),0,context_shape);
1389 static int combining_lexical_Thai(WCHAR c)
1391 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1393 switch(c)
1395 case 0xE31:
1396 case 0xE34:
1397 case 0xE35:
1398 case 0xE36:
1399 case 0xE37: return Thai_ABOVE1;
1400 case 0xE47:
1401 case 0xE4D: return Thai_ABOVE2;
1402 case 0xE48:
1403 case 0xE49:
1404 case 0xE4A:
1405 case 0xE4B: return Thai_ABOVE3;
1406 case 0xE4C:
1407 case 0xE4E: return Thai_ABOVE4;
1408 case 0xE38:
1409 case 0xE39: return Thai_BELOW1;
1410 case 0xE3A: return Thai_BELOW2;
1411 case 0xE33: return Thai_AM;
1412 default: return Thai_Norm;
1416 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1418 INT dirL;
1420 if (*pcGlyphs != cChars)
1422 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1423 return;
1426 if (!psa->fLogicalOrder && psa->fRTL)
1427 dirL = -1;
1428 else
1429 dirL = 1;
1431 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1434 static int combining_lexical_Lao(WCHAR c)
1436 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1438 switch(c)
1440 case 0xEB1:
1441 case 0xEB4:
1442 case 0xEB5:
1443 case 0xEB6:
1444 case 0xEB7:
1445 case 0xEBB:
1446 case 0xECD: return Lao_ABOVE1;
1447 case 0xEC8:
1448 case 0xEC9:
1449 case 0xECA:
1450 case 0xECB:
1451 case 0xECC: return Lao_ABOVE2;
1452 case 0xEBC: return Lao_BELOW1;
1453 case 0xEB8:
1454 case 0xEB9: return Lao_BELOW2;
1455 case 0xEB3: return Lao_AM;
1456 default: return Lao_Norm;
1460 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1462 INT dirL;
1464 if (*pcGlyphs != cChars)
1466 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1467 return;
1470 if (!psa->fLogicalOrder && psa->fRTL)
1471 dirL = -1;
1472 else
1473 dirL = 1;
1475 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1478 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1480 int i;
1482 /* Replace */
1483 pwOutChars[cWalk] = replacements[0];
1484 cWalk=cWalk+1;
1486 /* Insert */
1487 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1489 int j;
1490 for (j = *pcChars; j > cWalk; j--)
1491 pwOutChars[j] = pwOutChars[j-1];
1492 *pcChars= *pcChars+1;
1493 pwOutChars[cWalk] = replacements[i];
1494 cWalk = cWalk+1;
1498 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1500 int i;
1501 int cWalk;
1503 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1505 for (i = 0; vowels[i].base != 0x0; i++)
1507 if (pwOutChars[cWalk] == vowels[i].base)
1509 int o = 0;
1510 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1511 if (vowels[i].parts[1]) { cWalk++; o++; }
1512 if (vowels[i].parts[2]) { cWalk++; o++; }
1513 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1514 break;
1520 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1522 int i;
1523 int offset = 0;
1524 int cWalk;
1526 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1528 for (i = 0; consonants[i].output!= 0x0; i++)
1530 int j;
1531 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1532 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1533 break;
1535 if (consonants[i].parts[j]==0x0) /* matched all */
1537 int k;
1538 j--;
1539 pwOutChars[cWalk] = consonants[i].output;
1540 for(k = cWalk+1; k < *pcChars - j; k++)
1541 pwOutChars[k] = pwOutChars[k+j];
1542 *pcChars = *pcChars - j;
1543 for (k = j ; k > 0; k--)
1544 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1545 offset += j;
1546 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1547 pwLogClust[k]--;
1548 break;
1551 cWalk++;
1555 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1557 if (s->ralf >= 0)
1559 int j;
1560 WORD Ra = pwChar[s->start];
1561 WORD H = pwChar[s->start+1];
1563 TRACE("Doing reorder of Ra to %i\n",s->base);
1564 for (j = s->start; j < s->base-1; j++)
1565 pwChar[j] = pwChar[j+2];
1566 pwChar[s->base-1] = Ra;
1567 pwChar[s->base] = H;
1569 s->ralf = s->base-1;
1570 s->base -= 2;
1574 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1576 if (s->ralf >= 0)
1578 int j,loc;
1579 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1580 WORD Ra = pwChar[s->start];
1581 WORD H = pwChar[s->start+1];
1582 for (loc = s->end; loc > stop; loc--)
1583 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1584 break;
1586 TRACE("Doing reorder of Ra to %i\n",loc);
1587 for (j = s->start; j < loc-1; j++)
1588 pwChar[j] = pwChar[j+2];
1589 pwChar[loc-1] = Ra;
1590 pwChar[loc] = H;
1592 s->ralf = loc-1;
1593 s->base -= 2;
1594 if (s->blwf >= 0) s->blwf -= 2;
1595 if (s->pref >= 0) s->pref -= 2;
1599 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1601 if (s->ralf >= 0)
1603 int j;
1604 WORD Ra = pwChar[s->start];
1605 WORD H = pwChar[s->start+1];
1607 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1608 for (j = s->start; j < s->end-1; j++)
1609 pwChar[j] = pwChar[j+2];
1610 pwChar[s->end-1] = Ra;
1611 pwChar[s->end] = H;
1613 s->ralf = s->end-1;
1614 s->base -= 2;
1615 if (s->blwf >= 0) s->blwf -= 2;
1616 if (s->pref >= 0) s->pref -= 2;
1620 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1622 int i;
1624 /* reorder Matras */
1625 if (s->end > s->base)
1627 for (i = 1; i <= s->end-s->base; i++)
1629 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1631 int j;
1632 WCHAR c = pwChar[s->base+i];
1633 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1634 for (j = s->base+i; j > s->base; j--)
1635 pwChar[j] = pwChar[j-1];
1636 pwChar[s->base] = c;
1638 if (s->ralf >= s->base) s->ralf++;
1639 if (s->blwf >= s->base) s->blwf++;
1640 if (s->pref >= s->base) s->pref++;
1641 s->base ++;
1647 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1649 int i;
1651 /* reorder Matras */
1652 if (s->end > s->base)
1654 for (i = 1; i <= s->end-s->base; i++)
1656 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1658 int j;
1659 WCHAR c = pwChar[s->base+i];
1660 TRACE("Doing reorder of %x to %i\n",c,s->start);
1661 for (j = s->base+i; j > s->start; j--)
1662 pwChar[j] = pwChar[j-1];
1663 pwChar[s->start] = c;
1665 if (s->ralf >= 0) s->ralf++;
1666 if (s->blwf >= 0) s->blwf++;
1667 if (s->pref >= 0) s->pref++;
1668 s->base ++;
1674 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1676 if (s->blwf >= 0 && g->blwf > g->base)
1678 int j,loc;
1679 int g_offset;
1680 for (loc = s->end; loc > s->blwf; loc--)
1681 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1682 break;
1684 g_offset = (loc - s->blwf) - 1;
1686 if (loc != s->blwf)
1688 WORD blwf = glyphs[g->blwf];
1689 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1690 /* do not care about the pwChar array anymore, just the glyphs */
1691 for (j = 0; j < g_offset; j++)
1692 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1693 glyphs[g->blwf + g_offset] = blwf;
1698 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1700 int i;
1702 /* reorder previously moved Matras to correct position*/
1703 for (i = s->start; i < s->base; i++)
1705 if (lexical(pwChar[i]) == lex_Matra_pre)
1707 int j;
1708 int g_start = g->start + i - s->start;
1709 if (g_start < g->base -1 )
1711 WCHAR og = glyphs[g_start];
1712 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1713 for (j = g_start; j < g->base-1; j++)
1714 glyphs[j] = glyphs[j+1];
1715 glyphs[g->base-1] = og;
1721 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1723 if (s->pref >= 0 && g->pref > g->base)
1725 int j;
1726 WCHAR og = glyphs[g->pref];
1727 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1728 for (j = g->pref; j > g->base; j--)
1729 glyphs[j] = glyphs[j-1];
1730 glyphs[g->base] = og;
1734 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1736 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1737 if (s->start == s->base && s->base == s->end) return;
1738 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1740 Reorder_Ra_follows_base(pwChar, s, lexical);
1741 Reorder_Matra_precede_base(pwChar, s, lexical);
1744 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1746 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1747 if (s->start == s->base && s->base == s->end) return;
1748 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1750 Reorder_Ra_follows_matra(pwChar, s, lexical);
1751 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1754 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1756 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1757 if (s->start == s->base && s->base == s->end) return;
1758 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1760 Reorder_Ra_follows_base(pwChar, s, lexical);
1761 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1764 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1766 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1767 if (s->start == s->base && s->base == s->end) return;
1768 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1770 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1771 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1774 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1776 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1777 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1778 if (s->start == s->base && s->base == s->end) return;
1779 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1781 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1784 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1786 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1787 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1788 if (s->start == s->base && s->base == s->end) return;
1789 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1791 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1792 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1796 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1798 if (shift == 0)
1799 return;
1801 if (glyph_index->start > index)
1802 glyph_index->start += shift;
1803 if (glyph_index->base > index)
1804 glyph_index->base+= shift;
1805 if (glyph_index->end > index)
1806 glyph_index->end+= shift;
1807 if (glyph_index->ralf > index)
1808 glyph_index->ralf+= shift;
1809 if (glyph_index->blwf > index)
1810 glyph_index->blwf+= shift;
1811 if (glyph_index->pref > index)
1812 glyph_index->pref+= shift;
1815 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 )
1817 int index = glyph_index->start;
1819 if (!feature)
1820 return;
1822 while(index <= glyph_index->end)
1824 INT nextIndex;
1825 INT prevCount = *pcGlyphs;
1826 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1827 if (nextIndex > GSUB_E_NOGLYPH)
1829 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1830 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1831 index = nextIndex;
1833 else
1834 index++;
1838 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1840 int i = 0;
1841 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)))))
1842 i++;
1843 if (index + i <= end-1)
1844 return index + i;
1845 else
1846 return -1;
1849 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)
1851 INT index, nextIndex;
1852 INT count,g_offset;
1854 count = syllable->base - syllable->start;
1856 g_offset = 0;
1857 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1858 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1860 INT prevCount = *pcGlyphs;
1861 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1862 if (nextIndex > GSUB_E_NOGLYPH)
1864 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1865 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1866 g_offset += (*pcGlyphs - prevCount);
1869 index+=2;
1870 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1874 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)
1876 INT nextIndex;
1877 INT prevCount = *pcGlyphs;
1879 if (syllable->ralf >= 0)
1881 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1882 if (nextIndex > GSUB_E_NOGLYPH)
1884 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1885 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1890 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1892 int i = 0;
1893 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1894 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1895 is_consonant(lexical(pwChars[index+i+1])))))
1896 i++;
1897 if (index + i <= end-1)
1898 return index+i;
1899 else
1900 return -1;
1903 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)
1905 INT index, nextIndex;
1906 INT count, g_offset=0;
1907 INT ralf = syllable->ralf;
1909 count = syllable->end - syllable->base;
1911 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
1913 while (index >= 0)
1915 INT prevCount = *pcGlyphs;
1916 if (ralf >=0 && ralf < index)
1918 g_offset--;
1919 ralf = -1;
1922 if (!modern)
1924 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1925 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1926 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1929 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
1930 if (nextIndex > GSUB_E_NOGLYPH)
1932 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1933 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
1934 g_offset += (*pcGlyphs - prevCount);
1936 else if (!modern)
1938 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1939 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1940 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1943 index+=2;
1944 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
1948 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)
1950 int c;
1951 int overall_shift = 0;
1952 LoadedFeature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
1953 LoadedFeature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
1954 LoadedFeature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
1955 LoadedFeature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
1956 LoadedFeature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
1957 LoadedFeature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
1958 LoadedFeature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
1959 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
1960 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
1961 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
1962 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
1963 IndicSyllable glyph_indexs;
1965 for (c = 0; c < syllable_count; c++)
1967 int old_end;
1968 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
1969 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
1970 old_end = glyph_indexs.end;
1972 if (locl)
1974 TRACE("applying feature locl\n");
1975 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
1977 if (nukt)
1979 TRACE("applying feature nukt\n");
1980 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
1982 if (akhn)
1984 TRACE("applying feature akhn\n");
1985 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
1988 if (rphf)
1989 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
1990 if (rkrf)
1992 TRACE("applying feature rkrf\n");
1993 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
1995 if (pref)
1996 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
1997 if (blwf)
1999 if (!modern)
2000 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2002 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2005 if (half)
2006 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2007 if (pstf)
2009 TRACE("applying feature pstf\n");
2010 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2012 if (vatu)
2014 TRACE("applying feature vatu\n");
2015 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2017 if (cjct)
2019 TRACE("applying feature cjct\n");
2020 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2023 if (second_reorder)
2024 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2026 overall_shift += glyph_indexs.end - old_end;
2030 static inline int unicode_lex(WCHAR c)
2032 int type;
2034 if (!c) return lex_Generic;
2035 if (c == 0x200D) return lex_ZWJ;
2036 if (c == 0x200C) return lex_ZWNJ;
2037 if (c == 0x00A0) return lex_NBSP;
2039 type = get_table_entry( indic_syllabic_table, c );
2041 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2043 switch( type )
2045 case 0x0d07: /* Unknown */
2046 case 0x0e07: /* Unknwon */
2047 default: return lex_Generic;
2048 case 0x0001:
2049 case 0x0002:
2050 case 0x0011:
2051 case 0x0012:
2052 case 0x0013:
2053 case 0x0014: return lex_Modifier;
2054 case 0x0003:
2055 case 0x0009:
2056 case 0x000a:
2057 case 0x000b:
2058 case 0x000d:
2059 case 0x000e:
2060 case 0x000f:
2061 case 0x0010: return lex_Consonant;
2062 case 0x0004: return lex_Nukta;
2063 case 0x0005: return lex_Halant;
2064 case 0x0006:
2065 case 0x0008: return lex_Vowel;
2066 case 0x0007:
2067 case 0x0107: return lex_Matra_post;
2068 case 0x0207:
2069 case 0x0307: return lex_Matra_pre;
2070 case 0x0807:
2071 case 0x0907:
2072 case 0x0a07:
2073 case 0x0b07:
2074 case 0x0c07:
2075 case 0x0407: return lex_Composed_Vowel;
2076 case 0x0507: return lex_Matra_above;
2077 case 0x0607: return lex_Matra_below;
2078 case 0x000c: return lex_Ra;
2082 static int sinhala_lex(WCHAR c)
2084 switch (c)
2086 case 0x0DDA:
2087 case 0x0DDD:
2088 case 0x0DDC:
2089 case 0x0DDE: return lex_Matra_post;
2090 default:
2091 return unicode_lex(c);
2095 static const VowelComponents Sinhala_vowels[] = {
2096 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2097 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2098 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2099 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2100 {0x0000, {0x0000,0x0000,0x0}}};
2102 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2104 int cCount = cChars;
2105 int i;
2106 WCHAR *input;
2107 IndicSyllable *syllables = NULL;
2108 int syllable_count = 0;
2110 if (*pcGlyphs != cChars)
2112 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2113 return;
2116 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2118 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2120 /* Step 1: Decompose multi part vowels */
2121 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2123 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2125 /* Step 2: Reorder within Syllables */
2126 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2127 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2129 /* Step 3: Strip dangling joiners */
2130 for (i = 0; i < cCount; i++)
2132 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2133 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2134 input[i] = 0x0020;
2137 /* Step 4: Base Form application to syllables */
2138 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2139 *pcGlyphs = cCount;
2140 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2142 HeapFree(GetProcessHeap(),0,input);
2143 HeapFree(GetProcessHeap(),0,syllables);
2146 static int devanagari_lex(WCHAR c)
2148 switch (c)
2150 case 0x0930: return lex_Ra;
2151 default:
2152 return unicode_lex(c);
2156 static const ConsonantComponents Devanagari_consonants[] ={
2157 {{0x0928, 0x093C, 0x00000}, 0x0929},
2158 {{0x0930, 0x093C, 0x00000}, 0x0931},
2159 {{0x0933, 0x093C, 0x00000}, 0x0934},
2160 {{0x0915, 0x093C, 0x00000}, 0x0958},
2161 {{0x0916, 0x093C, 0x00000}, 0x0959},
2162 {{0x0917, 0x093C, 0x00000}, 0x095A},
2163 {{0x091C, 0x093C, 0x00000}, 0x095B},
2164 {{0x0921, 0x093C, 0x00000}, 0x095C},
2165 {{0x0922, 0x093C, 0x00000}, 0x095D},
2166 {{0x092B, 0x093C, 0x00000}, 0x095E},
2167 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2169 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2171 int cCount = cChars;
2172 WCHAR *input;
2173 IndicSyllable *syllables = NULL;
2174 int syllable_count = 0;
2175 BOOL modern = get_GSUB_Indic2(psa, psc);
2177 if (*pcGlyphs != cChars)
2179 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2180 return;
2183 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2184 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2186 /* Step 1: Compose Consonant and Nukta */
2187 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2188 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2190 /* Step 2: Reorder within Syllables */
2191 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2192 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2193 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2194 *pcGlyphs = cCount;
2196 /* Step 3: Base Form application to syllables */
2197 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2199 HeapFree(GetProcessHeap(),0,input);
2200 HeapFree(GetProcessHeap(),0,syllables);
2203 static int bengali_lex(WCHAR c)
2205 switch (c)
2207 case 0x09B0: return lex_Ra;
2208 default:
2209 return unicode_lex(c);
2213 static const VowelComponents Bengali_vowels[] = {
2214 {0x09CB, {0x09C7,0x09BE,0x0000}},
2215 {0x09CC, {0x09C7,0x09D7,0x0000}},
2216 {0x0000, {0x0000,0x0000,0x0000}}};
2218 static const ConsonantComponents Bengali_consonants[] = {
2219 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2220 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2221 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2222 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2223 {{0x0000,0x0000,0x0000}, 0x0000}};
2225 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2227 int cCount = cChars;
2228 WCHAR *input;
2229 IndicSyllable *syllables = NULL;
2230 int syllable_count = 0;
2231 BOOL modern = get_GSUB_Indic2(psa, psc);
2233 if (*pcGlyphs != cChars)
2235 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2236 return;
2239 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2240 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2242 /* Step 1: Decompose Vowels and Compose Consonants */
2243 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2244 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2245 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2247 /* Step 2: Reorder within Syllables */
2248 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2249 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2250 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2251 *pcGlyphs = cCount;
2253 /* Step 3: Initial form is only applied to the beginning of words */
2254 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2256 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2258 int index = cCount;
2259 int gCount = 1;
2260 if (index > 0) index++;
2262 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2266 /* Step 4: Base Form application to syllables */
2267 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2269 HeapFree(GetProcessHeap(),0,input);
2270 HeapFree(GetProcessHeap(),0,syllables);
2273 static int gurmukhi_lex(WCHAR c)
2275 if (c == 0x0A71)
2276 return lex_Modifier;
2277 else
2278 return unicode_lex(c);
2281 static const ConsonantComponents Gurmukhi_consonants[] = {
2282 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2283 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2284 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2285 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2286 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2287 {{0x0000,0x0000,0x0000}, 0x0000}};
2289 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2291 int cCount = cChars;
2292 WCHAR *input;
2293 IndicSyllable *syllables = NULL;
2294 int syllable_count = 0;
2295 BOOL modern = get_GSUB_Indic2(psa, psc);
2297 if (*pcGlyphs != cChars)
2299 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2300 return;
2303 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2304 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2306 /* Step 1: Compose Consonants */
2307 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2308 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2310 /* Step 2: Reorder within Syllables */
2311 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2312 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2313 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2314 *pcGlyphs = cCount;
2316 /* Step 3: Base Form application to syllables */
2317 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2319 HeapFree(GetProcessHeap(),0,input);
2320 HeapFree(GetProcessHeap(),0,syllables);
2323 static int gujarati_lex(WCHAR c)
2325 switch (c)
2327 case 0x0AB0: return lex_Ra;
2328 default:
2329 return unicode_lex(c);
2333 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2335 int cCount = cChars;
2336 WCHAR *input;
2337 IndicSyllable *syllables = NULL;
2338 int syllable_count = 0;
2339 BOOL modern = get_GSUB_Indic2(psa, psc);
2341 if (*pcGlyphs != cChars)
2343 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2344 return;
2347 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2348 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2350 /* Step 1: Reorder within Syllables */
2351 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2352 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2353 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2354 *pcGlyphs = cCount;
2356 /* Step 2: Base Form application to syllables */
2357 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2359 HeapFree(GetProcessHeap(),0,input);
2360 HeapFree(GetProcessHeap(),0,syllables);
2363 static int oriya_lex(WCHAR c)
2365 switch (c)
2367 case 0x0B30: return lex_Ra;
2368 default:
2369 return unicode_lex(c);
2373 static const VowelComponents Oriya_vowels[] = {
2374 {0x0B48, {0x0B47,0x0B56,0x0000}},
2375 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2376 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2377 {0x0000, {0x0000,0x0000,0x0000}}};
2379 static const ConsonantComponents Oriya_consonants[] = {
2380 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2381 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2382 {{0x0000,0x0000,0x0000}, 0x0000}};
2384 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2386 int cCount = cChars;
2387 WCHAR *input;
2388 IndicSyllable *syllables = NULL;
2389 int syllable_count = 0;
2390 BOOL modern = get_GSUB_Indic2(psa, psc);
2392 if (*pcGlyphs != cChars)
2394 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2395 return;
2398 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2399 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2401 /* Step 1: Decompose Vowels and Compose Consonants */
2402 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2403 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2404 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2406 /* Step 2: Reorder within Syllables */
2407 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2408 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2409 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2410 *pcGlyphs = cCount;
2412 /* Step 3: Base Form application to syllables */
2413 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2415 HeapFree(GetProcessHeap(),0,input);
2416 HeapFree(GetProcessHeap(),0,syllables);
2419 static int tamil_lex(WCHAR c)
2421 return unicode_lex(c);
2424 static const VowelComponents Tamil_vowels[] = {
2425 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2426 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2427 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2428 {0x0000, {0x0000,0x0000,0x0000}}};
2430 static const ConsonantComponents Tamil_consonants[] = {
2431 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2432 {{0x0000,0x0000,0x0000}, 0x0000}};
2434 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2436 int cCount = cChars;
2437 WCHAR *input;
2438 IndicSyllable *syllables = NULL;
2439 int syllable_count = 0;
2440 BOOL modern = get_GSUB_Indic2(psa, psc);
2442 if (*pcGlyphs != cChars)
2444 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2445 return;
2448 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2449 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2451 /* Step 1: Decompose Vowels and Compose Consonants */
2452 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2453 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2454 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2456 /* Step 2: Reorder within Syllables */
2457 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2458 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2459 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2460 *pcGlyphs = cCount;
2462 /* Step 3: Base Form application to syllables */
2463 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2465 HeapFree(GetProcessHeap(),0,input);
2466 HeapFree(GetProcessHeap(),0,syllables);
2469 static int telugu_lex(WCHAR c)
2471 switch (c)
2473 case 0x0C43:
2474 case 0x0C44: return lex_Modifier;
2475 default:
2476 return unicode_lex(c);
2480 static const VowelComponents Telugu_vowels[] = {
2481 {0x0C48, {0x0C46,0x0C56,0x0000}},
2482 {0x0000, {0x0000,0x0000,0x0000}}};
2484 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2486 int cCount = cChars;
2487 WCHAR *input;
2488 IndicSyllable *syllables = NULL;
2489 int syllable_count = 0;
2490 BOOL modern = get_GSUB_Indic2(psa, psc);
2492 if (*pcGlyphs != cChars)
2494 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2495 return;
2498 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2499 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2501 /* Step 1: Decompose Vowels */
2502 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2503 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2505 /* Step 2: Reorder within Syllables */
2506 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2507 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2508 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2509 *pcGlyphs = cCount;
2511 /* Step 3: Base Form application to syllables */
2512 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2514 HeapFree(GetProcessHeap(),0,input);
2515 HeapFree(GetProcessHeap(),0,syllables);
2518 static int kannada_lex(WCHAR c)
2520 switch (c)
2522 case 0x0CB0: return lex_Ra;
2523 default:
2524 return unicode_lex(c);
2528 static const VowelComponents Kannada_vowels[] = {
2529 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2530 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2531 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2532 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2533 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2534 {0x0000, {0x0000,0x0000,0x0000}}};
2536 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2538 int cCount = cChars;
2539 WCHAR *input;
2540 IndicSyllable *syllables = NULL;
2541 int syllable_count = 0;
2542 BOOL modern = get_GSUB_Indic2(psa, psc);
2544 if (*pcGlyphs != cChars)
2546 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2547 return;
2550 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2551 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2553 /* Step 1: Decompose Vowels */
2554 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2555 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2557 /* Step 2: Reorder within Syllables */
2558 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2559 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2560 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2561 *pcGlyphs = cCount;
2563 /* Step 3: Base Form application to syllables */
2564 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2566 HeapFree(GetProcessHeap(),0,input);
2567 HeapFree(GetProcessHeap(),0,syllables);
2570 static int malayalam_lex(WCHAR c)
2572 return unicode_lex(c);
2575 static const VowelComponents Malayalam_vowels[] = {
2576 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2577 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2578 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2579 {0x0000, {0x0000,0x0000,0x0000}}};
2581 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2583 int cCount = cChars;
2584 WCHAR *input;
2585 IndicSyllable *syllables = NULL;
2586 int syllable_count = 0;
2587 BOOL modern = get_GSUB_Indic2(psa, psc);
2589 if (*pcGlyphs != cChars)
2591 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2592 return;
2595 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2596 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2598 /* Step 1: Decompose Vowels */
2599 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2600 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2602 /* Step 2: Reorder within Syllables */
2603 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2604 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2605 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2606 *pcGlyphs = cCount;
2608 /* Step 3: Base Form application to syllables */
2609 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2611 HeapFree(GetProcessHeap(),0,input);
2612 HeapFree(GetProcessHeap(),0,syllables);
2615 static int khmer_lex(WCHAR c)
2617 return unicode_lex(c);
2620 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2622 int cCount = cChars;
2623 WCHAR *input;
2624 IndicSyllable *syllables = NULL;
2625 int syllable_count = 0;
2627 if (*pcGlyphs != cChars)
2629 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2630 return;
2633 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2634 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2636 /* Step 1: Reorder within Syllables */
2637 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2638 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2639 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2640 *pcGlyphs = cCount;
2642 /* Step 2: Base Form application to syllables */
2643 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2645 HeapFree(GetProcessHeap(),0,input);
2646 HeapFree(GetProcessHeap(),0,syllables);
2649 static inline BOOL mongolian_wordbreak(WCHAR chr)
2651 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2654 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2656 INT *context_shape;
2657 INT dirL;
2658 int i;
2660 if (*pcGlyphs != cChars)
2662 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2663 return;
2666 if (!psa->fLogicalOrder && psa->fRTL)
2667 dirL = -1;
2668 else
2669 dirL = 1;
2671 load_ot_tables(hdc, psc);
2673 if (!psc->GSUB_Table)
2674 return;
2676 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2678 for (i = 0; i < cChars; i++)
2680 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2682 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2683 context_shape[i] = Xn;
2684 else
2685 context_shape[i] = Xl;
2687 else
2689 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2690 context_shape[i] = Xr;
2691 else
2692 context_shape[i] = Xm;
2696 /* Contextual Shaping */
2697 i = 0;
2698 while(i < *pcGlyphs)
2700 INT nextIndex;
2701 INT prevCount = *pcGlyphs;
2702 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2703 if (nextIndex > GSUB_E_NOGLYPH)
2705 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2706 i = nextIndex;
2708 else
2709 i++;
2712 HeapFree(GetProcessHeap(),0,context_shape);
2715 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)
2717 int i,k;
2719 for (i = 0; i < cGlyphs; i++)
2721 int char_index[20];
2722 int char_count = 0;
2724 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2725 if (k>=0)
2727 for (; k < cChars && pwLogClust[k] == i; k++)
2728 char_index[char_count++] = k;
2731 if (char_count == 0)
2732 continue;
2734 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2736 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2737 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2739 else
2740 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2743 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2744 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2747 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 )
2749 int i,k;
2750 int initGlyph, finaGlyph;
2751 INT dirR, dirL;
2752 BYTE *spaces;
2754 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2755 memset(spaces,0,cGlyphs);
2757 if (!psa->fLogicalOrder && psa->fRTL)
2759 initGlyph = cGlyphs-1;
2760 finaGlyph = 0;
2761 dirR = 1;
2762 dirL = -1;
2764 else
2766 initGlyph = 0;
2767 finaGlyph = cGlyphs-1;
2768 dirR = -1;
2769 dirL = 1;
2772 for (i = 0; i < cGlyphs; i++)
2774 for (k = 0; k < cChars; k++)
2775 if (pwLogClust[k] == i)
2777 if (pwcChars[k] == 0x0020)
2778 spaces[i] = 1;
2782 for (i = 0; i < cGlyphs; i++)
2784 int char_index[20];
2785 int char_count = 0;
2786 BOOL isInit, isFinal;
2788 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2789 if (k>=0)
2791 for (; k < cChars && pwLogClust[k] == i; k++)
2792 char_index[char_count++] = k;
2795 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2796 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2798 if (char_count == 0)
2799 continue;
2801 if (char_count == 1)
2803 if (pwcChars[char_index[0]] == 0x0020) /* space */
2805 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2806 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2808 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2809 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2810 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2812 if (!isInit && !isFinal)
2813 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2814 else if (isInit)
2815 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2816 else
2817 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2819 else if (!isInit)
2821 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2822 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2823 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2824 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2825 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2826 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2827 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2828 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2829 else
2830 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2832 else if (!isInit && !isFinal)
2833 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2834 else
2835 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2837 else if (char_count == 2)
2839 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2840 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2841 else if (!isInit)
2842 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2843 else
2844 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2846 else if (!isInit && !isFinal)
2847 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2848 else
2849 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2852 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2853 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2854 HeapFree(GetProcessHeap(),0,spaces);
2857 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2859 int i,k;
2861 for (i = 0; i < cGlyphs; i++)
2863 int char_index[20];
2864 int char_count = 0;
2866 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2867 if (k>=0)
2869 for (; k < cChars && pwLogClust[k] == i; k++)
2870 char_index[char_count++] = k;
2873 if (char_count == 0)
2874 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2875 else
2877 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2878 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2879 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2883 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2884 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2887 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 )
2889 int i;
2890 int finaGlyph;
2891 INT dirL;
2893 if (!psa->fLogicalOrder && psa->fRTL)
2895 finaGlyph = 0;
2896 dirL = -1;
2898 else
2900 finaGlyph = cGlyphs-1;
2901 dirL = 1;
2904 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2906 for (i = 0; i < cGlyphs; i++)
2908 int k;
2909 int char_index[20];
2910 int char_count = 0;
2912 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2913 if (k>=0)
2915 for (; k < cChars && pwLogClust[k] == i; k++)
2916 char_index[char_count++] = k;
2919 if (i == finaGlyph)
2920 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2921 else
2922 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2924 if (char_count == 0)
2925 continue;
2927 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2928 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2930 /* handle Thai SARA AM (U+0E33) differently than GDEF */
2931 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
2932 pGlyphProp[i].sva.fClusterStart = 0;
2935 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2937 /* Do not allow justification between marks and their base */
2938 for (i = 0; i < cGlyphs; i++)
2940 if (!pGlyphProp[i].sva.fClusterStart)
2941 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2945 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)
2947 int i,k;
2949 for (i = 0; i < cGlyphs; i++)
2951 int char_index[20];
2952 int char_count = 0;
2954 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2955 if (k>=0)
2957 for (; k < cChars && pwLogClust[k] == i; k++)
2958 char_index[char_count++] = k;
2961 if (char_count == 0)
2962 continue;
2964 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2966 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2967 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2969 else
2970 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2972 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2973 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2976 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)
2978 int i,k;
2980 for (i = 0; i < cGlyphs; i++)
2982 int char_index[20];
2983 int char_count = 0;
2985 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2986 if (k>=0)
2988 for (; k < cChars && pwLogClust[k] == i; k++)
2989 char_index[char_count++] = k;
2992 if (char_count == 0)
2993 continue;
2995 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2997 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2998 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3000 else
3001 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3003 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3004 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3006 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3007 for (i = 0; i < cGlyphs; i++)
3009 if (!pGlyphProp[i].sva.fClusterStart)
3011 pGlyphProp[i].sva.fDiacritic = 0;
3012 pGlyphProp[i].sva.fZeroWidth = 0;
3017 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)
3019 int i,k;
3021 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3022 for (i = 0; i < cGlyphs; i++)
3024 int char_index[20];
3025 int char_count = 0;
3027 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3028 if (k>=0)
3030 for (; k < cChars && pwLogClust[k] == i; k++)
3031 char_index[char_count++] = k;
3034 if (override_gsub)
3036 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3037 pGlyphProp[i].sva.fDiacritic = FALSE;
3038 pGlyphProp[i].sva.fZeroWidth = FALSE;
3041 if (char_count == 0)
3043 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3044 continue;
3047 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3049 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3050 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3052 else
3053 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3055 pGlyphProp[i].sva.fClusterStart = 0;
3056 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3057 switch (lexical(pwcChars[char_index[k]]))
3059 case lex_Matra_pre:
3060 case lex_Matra_post:
3061 case lex_Matra_above:
3062 case lex_Matra_below:
3063 case lex_Modifier:
3064 case lex_Halant:
3065 break;
3066 case lex_ZWJ:
3067 case lex_ZWNJ:
3068 /* check for dangling joiners */
3069 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3070 pGlyphProp[i].sva.fClusterStart = 1;
3071 else
3072 k = char_count;
3073 break;
3074 default:
3075 pGlyphProp[i].sva.fClusterStart = 1;
3076 break;
3080 if (use_syllables)
3082 IndicSyllable *syllables = NULL;
3083 int syllable_count = 0;
3084 BOOL modern = get_GSUB_Indic2(psa, psc);
3086 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3088 for (i = 0; i < syllable_count; i++)
3090 int j;
3091 WORD g = pwLogClust[syllables[i].start];
3092 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3094 if (pwLogClust[j] != g)
3096 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3097 pwLogClust[j] = g;
3102 HeapFree(GetProcessHeap(), 0, syllables);
3105 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3108 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 )
3110 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3113 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 )
3115 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3118 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 )
3120 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3123 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 )
3125 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3128 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 )
3130 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3133 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 )
3135 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3138 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 )
3140 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3143 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 )
3145 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3148 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 )
3150 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3153 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 )
3155 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3158 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 )
3160 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3163 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)
3165 if (ShapingData[psa->eScript].charGlyphPropProc)
3166 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3167 else
3168 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3171 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3173 load_ot_tables(hdc, psc);
3175 if (ShapingData[psa->eScript].contextProc)
3176 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3179 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)
3181 int i;
3182 INT dirL;
3184 if (!rpRangeProperties)
3185 return;
3187 load_ot_tables(hdc, psc);
3189 if (!psc->GSUB_Table)
3190 return;
3192 if (!psa->fLogicalOrder && psa->fRTL)
3193 dirL = -1;
3194 else
3195 dirL = 1;
3197 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3199 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3200 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3204 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3206 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3207 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3209 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3212 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3214 LoadedFeature *feature;
3215 int i;
3217 if (!ShapingData[psa->eScript].requiredFeatures)
3218 return S_OK;
3220 load_ot_tables(hdc, psc);
3222 /* we need to have at least one of the required features */
3223 i = 0;
3224 while (ShapingData[psa->eScript].requiredFeatures[i])
3226 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3227 if (feature)
3228 return S_OK;
3229 i++;
3232 return USP_E_SCRIPT_NOT_IN_FONT;
3235 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3236 SCRIPT_ANALYSIS *psa, int cMaxTags,
3237 OPENTYPE_TAG *pScriptTags, int *pcTags)
3239 HRESULT hr;
3240 OPENTYPE_TAG searching = 0x00000000;
3242 load_ot_tables(hdc, psc);
3244 if (psa && scriptInformation[psa->eScript].scriptTag)
3245 searching = scriptInformation[psa->eScript].scriptTag;
3247 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3248 if (FAILED(hr))
3249 *pcTags = 0;
3250 return hr;
3253 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3254 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3255 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3256 int *pcTags)
3258 HRESULT hr;
3259 OPENTYPE_TAG searching = 0x00000000;
3260 BOOL fellback = FALSE;
3262 load_ot_tables(hdc, psc);
3264 if (psa && psc->userLang != 0)
3265 searching = psc->userLang;
3267 hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL);
3268 if (FAILED(hr))
3270 fellback = TRUE;
3271 hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL);
3274 if (FAILED(hr) || fellback)
3275 *pcTags = 0;
3276 if (SUCCEEDED(hr) && fellback && psa)
3277 hr = E_INVALIDARG;
3278 return hr;
3281 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3282 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3283 OPENTYPE_TAG tagLangSys, int cMaxTags,
3284 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3286 HRESULT hr;
3287 BOOL filter = FALSE;
3289 load_ot_tables(hdc, psc);
3291 if (psa && scriptInformation[psa->eScript].scriptTag)
3293 FIXME("Filtering not implemented\n");
3294 filter = TRUE;
3297 hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL);
3299 if (FAILED(hr))
3300 *pcTags = 0;
3301 return hr;