po: Update French translation.
[wine.git] / dlls / usp10 / shape.c
blob0291f17154c6a0151c7198662eabe27c7d3a6038
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_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
63 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
65 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
67 static void ShapeCharGlyphProp_Default( 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_Control( 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_Latin( 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_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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
78 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 );
79 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 );
80 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 );
81 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 );
82 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 );
83 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 );
84 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 );
85 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 );
87 extern const unsigned short indic_syllabic_table[];
88 extern const unsigned short wine_shaping_table[];
89 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
91 enum joining_types {
92 jtU,
93 jtT,
94 jtR,
95 jtL,
96 jtD,
97 jtC
100 enum joined_forms {
101 Xn=0,
105 /* Syriac Alaph */
106 Afj,
107 Afn,
111 typedef struct tagVowelComponents
113 WCHAR base;
114 WCHAR parts[3];
115 } VowelComponents;
117 typedef struct tagConsonantComponents
119 WCHAR parts[3];
120 WCHAR output;
121 } ConsonantComponents;
123 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
125 typedef int (*combining_lexical_function)(WCHAR c);
127 /* the orders of joined_forms and contextual_features need to line up */
128 static const char* contextual_features[] =
130 "isol",
131 "fina",
132 "init",
133 "medi",
134 /* Syriac Alaph */
135 "med2",
136 "fin2",
137 "fin3"
140 static OPENTYPE_FEATURE_RECORD standard_features[] =
142 { MS_MAKE_TAG('c','c','m','p'), 1},
143 { MS_MAKE_TAG('l','o','c','l'), 1},
146 static OPENTYPE_FEATURE_RECORD latin_features[] =
148 { MS_MAKE_TAG('l','o','c','l'), 1},
149 { MS_MAKE_TAG('c','c','m','p'), 1},
150 { MS_MAKE_TAG('l','i','g','a'), 1},
151 { MS_MAKE_TAG('c','l','i','g'), 1},
154 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
156 { MS_MAKE_TAG('k','e','r','n'), 1},
157 { MS_MAKE_TAG('m','a','r','k'), 1},
158 { MS_MAKE_TAG('m','k','m','k'), 1},
161 static OPENTYPE_FEATURE_RECORD arabic_features[] =
163 { MS_MAKE_TAG('r','l','i','g'), 1},
164 { MS_MAKE_TAG('c','a','l','t'), 1},
165 { MS_MAKE_TAG('l','i','g','a'), 1},
166 { MS_MAKE_TAG('d','l','i','g'), 1},
167 { MS_MAKE_TAG('c','s','w','h'), 1},
168 { MS_MAKE_TAG('m','s','e','t'), 1},
171 static const char* required_arabic_features[] =
173 "fina",
174 "init",
175 "medi",
176 "rlig",
177 NULL
180 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
182 { MS_MAKE_TAG('c','u','r','s'), 1},
183 { MS_MAKE_TAG('k','e','r','n'), 1},
184 { MS_MAKE_TAG('m','a','r','k'), 1},
185 { MS_MAKE_TAG('m','k','m','k'), 1},
188 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
190 { MS_MAKE_TAG('c','c','m','p'), 1},
191 { MS_MAKE_TAG('d','l','i','g'), 0},
194 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
196 { MS_MAKE_TAG('k','e','r','n'), 1},
197 { MS_MAKE_TAG('m','a','r','k'), 1},
200 static OPENTYPE_FEATURE_RECORD syriac_features[] =
202 { MS_MAKE_TAG('r','l','i','g'), 1},
203 { MS_MAKE_TAG('c','a','l','t'), 1},
204 { MS_MAKE_TAG('l','i','g','a'), 1},
205 { MS_MAKE_TAG('d','l','i','g'), 1},
208 static const char* required_syriac_features[] =
210 "fina",
211 "fin2",
212 "fin3",
213 "init",
214 "medi",
215 "med2",
216 "rlig",
217 NULL
220 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
222 { MS_MAKE_TAG('k','e','r','n'), 1},
223 { MS_MAKE_TAG('m','a','r','k'), 1},
224 { MS_MAKE_TAG('m','k','m','k'), 1},
227 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
229 /* Presentation forms */
230 { MS_MAKE_TAG('b','l','w','s'), 1},
231 { MS_MAKE_TAG('a','b','v','s'), 1},
232 { MS_MAKE_TAG('p','s','t','s'), 1},
235 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
237 { MS_MAKE_TAG('a','b','v','s'), 1},
238 { MS_MAKE_TAG('b','l','w','s'), 1},
241 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
243 { MS_MAKE_TAG('a','b','v','m'), 1},
244 { MS_MAKE_TAG('b','l','w','m'), 1},
247 static OPENTYPE_FEATURE_RECORD phags_features[] =
249 { MS_MAKE_TAG('a','b','v','s'), 1},
250 { MS_MAKE_TAG('b','l','w','s'), 1},
251 { MS_MAKE_TAG('c','a','l','t'), 1},
254 static OPENTYPE_FEATURE_RECORD thai_features[] =
256 { MS_MAKE_TAG('c','c','m','p'), 1},
259 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
261 { MS_MAKE_TAG('k','e','r','n'), 1},
262 { MS_MAKE_TAG('m','a','r','k'), 1},
263 { MS_MAKE_TAG('m','k','m','k'), 1},
266 static const char* required_lao_features[] =
268 "ccmp",
269 NULL
272 static const char* required_devanagari_features[] =
274 "nukt",
275 "akhn",
276 "rphf",
277 "blwf",
278 "half",
279 "vatu",
280 "pres",
281 "abvs",
282 "blws",
283 "psts",
284 "haln",
285 NULL
288 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
290 { MS_MAKE_TAG('p','r','e','s'), 1},
291 { MS_MAKE_TAG('a','b','v','s'), 1},
292 { MS_MAKE_TAG('b','l','w','s'), 1},
293 { MS_MAKE_TAG('p','s','t','s'), 1},
294 { MS_MAKE_TAG('h','a','l','n'), 1},
295 { MS_MAKE_TAG('c','a','l','t'), 1},
298 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
300 { MS_MAKE_TAG('k','e','r','n'), 1},
301 { MS_MAKE_TAG('d','i','s','t'), 1},
302 { MS_MAKE_TAG('a','b','v','m'), 1},
303 { MS_MAKE_TAG('b','l','w','m'), 1},
306 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
308 { MS_MAKE_TAG('l','i','g','a'), 1},
309 { MS_MAKE_TAG('c','l','i','g'), 1},
312 static const char* required_bengali_features[] =
314 "nukt",
315 "akhn",
316 "rphf",
317 "blwf",
318 "half",
319 "vatu",
320 "pstf",
321 "init",
322 "abvs",
323 "blws",
324 "psts",
325 "haln",
326 NULL
329 static const char* required_gurmukhi_features[] =
331 "nukt",
332 "akhn",
333 "rphf",
334 "blwf",
335 "half",
336 "pstf",
337 "vatu",
338 "cjct",
339 "pres",
340 "abvs",
341 "blws",
342 "psts",
343 "haln",
344 "calt",
345 NULL
348 static const char* required_oriya_features[] =
350 "nukt",
351 "akhn",
352 "rphf",
353 "blwf",
354 "pstf",
355 "cjct",
356 "pres",
357 "abvs",
358 "blws",
359 "psts",
360 "haln",
361 "calt",
362 NULL
365 static const char* required_tamil_features[] =
367 "nukt",
368 "akhn",
369 "rphf",
370 "pref",
371 "half",
372 "pres",
373 "abvs",
374 "blws",
375 "psts",
376 "haln",
377 "calt",
378 NULL
381 static const char* required_telugu_features[] =
383 "nukt",
384 "akhn",
385 "rphf",
386 "pref",
387 "half",
388 "pstf",
389 "cjct",
390 "pres",
391 "abvs",
392 "blws",
393 "psts",
394 "haln",
395 "calt",
396 NULL
399 static OPENTYPE_FEATURE_RECORD khmer_features[] =
401 { MS_MAKE_TAG('p','r','e','s'), 1},
402 { MS_MAKE_TAG('b','l','w','s'), 1},
403 { MS_MAKE_TAG('a','b','v','s'), 1},
404 { MS_MAKE_TAG('p','s','t','s'), 1},
405 { MS_MAKE_TAG('c','l','i','g'), 1},
408 static const char* required_khmer_features[] =
410 "pref",
411 "blwf",
412 "abvf",
413 "pstf",
414 "pres",
415 "blws",
416 "abvs",
417 "psts",
418 "clig",
419 NULL
422 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
424 { MS_MAKE_TAG('d','i','s','t'), 1},
425 { MS_MAKE_TAG('b','l','w','m'), 1},
426 { MS_MAKE_TAG('a','b','v','m'), 1},
427 { MS_MAKE_TAG('m','k','m','k'), 1},
430 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
432 { MS_MAKE_TAG('c','c','m','p'), 1},
433 { MS_MAKE_TAG('l','o','c','l'), 1},
434 { MS_MAKE_TAG('c','a','l','t'), 1},
435 { MS_MAKE_TAG('l','i','g','a'), 1},
438 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
440 { MS_MAKE_TAG('c','c','m','p'), 1},
441 { MS_MAKE_TAG('l','o','c','l'), 1},
442 { MS_MAKE_TAG('c','a','l','t'), 1},
443 { MS_MAKE_TAG('r','l','i','g'), 1},
446 typedef struct ScriptShapeDataTag {
447 TEXTRANGE_PROPERTIES defaultTextRange;
448 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
449 const char** requiredFeatures;
450 OPENTYPE_TAG newOtTag;
451 ContextualShapingProc contextProc;
452 ShapeCharGlyphPropProc charGlyphPropProc;
453 } ScriptShapeData;
455 /* in order of scripts */
456 static const ScriptShapeData ShapingData[] =
458 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
459 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
460 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
461 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
462 {{ standard_features, 2}, {NULL, 0}, NULL, 0, ContextualShape_Control, ShapeCharGlyphProp_Control},
463 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
464 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
465 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
466 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
467 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
468 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
469 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
470 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
471 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
472 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
473 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
474 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
475 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
476 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
477 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
478 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
479 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
480 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
481 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
482 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
483 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
497 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
498 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
499 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
500 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
501 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
502 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
503 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
504 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
505 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
506 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
511 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
512 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
513 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
516 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
521 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
522 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
523 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
524 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
526 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
527 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
528 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
529 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
530 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
531 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
532 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
533 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
534 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
535 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
536 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
537 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
538 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
539 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
542 extern scriptData scriptInformation[];
544 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
546 int i;
547 int out_index = GSUB_E_NOGLYPH;
549 TRACE("%i lookups\n", feature->lookup_count);
550 for (i = 0; i < feature->lookup_count; i++)
552 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
553 if (out_index != GSUB_E_NOGLYPH)
554 break;
556 if (out_index == GSUB_E_NOGLYPH)
557 TRACE("lookups found no glyphs\n");
558 else
560 int out2;
561 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
562 if (out2!=GSUB_E_NOGLYPH)
563 out_index = out2;
565 return out_index;
568 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
570 UINT charset;
572 if (psc->userScript != 0)
574 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
575 return ShapingData[psa->eScript].newOtTag;
576 else
577 return psc->userScript;
580 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
581 return ShapingData[psa->eScript].newOtTag;
583 if (scriptInformation[psa->eScript].scriptTag)
584 return scriptInformation[psa->eScript].scriptTag;
587 * fall back to the font charset
589 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
590 switch (charset)
592 case ANSI_CHARSET:
593 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
594 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
595 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
596 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
597 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
598 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
599 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
600 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
601 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
602 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
603 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
604 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
605 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
606 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
607 default: return MS_MAKE_TAG('l','a','t','n');
611 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
613 LoadedFeature *feature = NULL;
615 if (psc->GSUB_Table || psc->GPOS_Table)
617 int attempt = 2;
618 OPENTYPE_TAG tags;
619 OPENTYPE_TAG language;
620 OPENTYPE_TAG script = 0x00000000;
621 int cTags;
625 script = get_opentype_script(hdc,psa,psc,(attempt==2));
626 if (psc->userLang != 0)
627 language = psc->userLang;
628 else
629 language = MS_MAKE_TAG('d','f','l','t');
630 attempt--;
632 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
634 } while(attempt && !feature);
636 /* try in the default (latin) table */
637 if (!feature && !script)
638 OpenType_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]), tableType, 1, &tags, &cTags, &feature);
641 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
642 return feature;
645 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)
647 LoadedFeature *feature;
649 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
650 if (!feature)
651 return GSUB_E_NOFEATURE;
653 TRACE("applying feature %s\n",feat);
654 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
657 static VOID *load_gsub_table(HDC hdc)
659 VOID* GSUB_Table = NULL;
660 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
661 if (length != GDI_ERROR)
663 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
664 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
665 TRACE("Loaded GSUB table of %i bytes\n",length);
667 return GSUB_Table;
670 static VOID *load_gpos_table(HDC hdc)
672 VOID* GPOS_Table = NULL;
673 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
674 if (length != GDI_ERROR)
676 GPOS_Table = HeapAlloc(GetProcessHeap(),0,length);
677 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
678 TRACE("Loaded GPOS table of %i bytes\n",length);
680 return GPOS_Table;
683 static VOID *load_gdef_table(HDC hdc)
685 VOID* GDEF_Table = NULL;
686 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
687 if (length != GDI_ERROR)
689 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
690 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
691 TRACE("Loaded GDEF table of %i bytes\n",length);
693 return GDEF_Table;
696 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
698 if (!psc->GSUB_Table)
699 psc->GSUB_Table = load_gsub_table(hdc);
700 if (!psc->GPOS_Table)
701 psc->GPOS_Table = load_gpos_table(hdc);
702 if (!psc->GDEF_Table)
703 psc->GDEF_Table = load_gdef_table(hdc);
706 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)
708 WORD *glyphs;
709 INT glyph_count = count;
710 INT rc;
712 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
713 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
714 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
715 if (rc > GSUB_E_NOGLYPH)
716 rc = count - glyph_count;
717 else
718 rc = 0;
720 HeapFree(GetProcessHeap(),0,glyphs);
721 return rc;
724 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
726 int i;
728 for (i = 0; i < cGlyphs; i++)
730 if (!pGlyphProp[i].sva.fClusterStart)
732 int j;
733 for (j = 0; j < cChars; j++)
735 if (pwLogClust[j] == i)
737 int k = j;
738 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
739 k-=1;
740 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
741 pwLogClust[j] = pwLogClust[k];
748 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
750 if (changeCount == 0)
751 return;
752 else
754 int i;
755 int target_glyph = nextIndex - write_dir;
756 int seeking_glyph;
757 int target_index = -1;
758 int replacing_glyph = -1;
759 int changed = 0;
760 int top_logclust = 0;
762 if (changeCount > 0)
764 if (write_dir > 0)
765 target_glyph = nextIndex - changeCount;
766 else
767 target_glyph = nextIndex + (changeCount + 1);
770 seeking_glyph = target_glyph;
771 for (i = 0; i < chars; i++)
772 if (pwLogClust[i] > top_logclust)
773 top_logclust = pwLogClust[i];
775 do {
776 if (write_dir > 0)
777 for (i = 0; i < chars; i++)
779 if (pwLogClust[i] == seeking_glyph)
781 target_index = i;
782 break;
785 else
786 for (i = chars - 1; i >= 0; i--)
788 if (pwLogClust[i] == seeking_glyph)
790 target_index = i;
791 break;
794 if (target_index == -1)
795 seeking_glyph ++;
797 while (target_index == -1 && seeking_glyph <= top_logclust);
799 if (target_index == -1)
801 ERR("Unable to find target glyph\n");
802 return;
805 if (changeCount < 0)
807 /* merge glyphs */
808 for(i = target_index; i < chars && i >= 0; i+=write_dir)
810 if (pwLogClust[i] == target_glyph)
811 continue;
812 if(pwLogClust[i] == replacing_glyph)
813 pwLogClust[i] = target_glyph;
814 else
816 changed--;
817 if (changed >= changeCount)
819 replacing_glyph = pwLogClust[i];
820 pwLogClust[i] = target_glyph;
822 else
823 break;
827 /* renumber trailing indexes*/
828 for(i = target_index; i < chars && i >= 0; i+=write_dir)
830 if (pwLogClust[i] != target_glyph)
831 pwLogClust[i] += changeCount;
834 else
836 for(i = target_index; i < chars && i >= 0; i+=write_dir)
837 pwLogClust[i] += changeCount;
842 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 )
844 if (psc->GSUB_Table)
846 LoadedFeature *feature;
847 int lookup_index;
849 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
850 if (!feature)
851 return GSUB_E_NOFEATURE;
853 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
854 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
856 int i;
858 if (write_dir > 0)
859 i = 0;
860 else
861 i = *pcGlyphs-1;
862 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
863 while(i < *pcGlyphs && i >= 0)
865 INT nextIndex;
866 INT prevCount = *pcGlyphs;
868 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
869 if (*pcGlyphs != prevCount)
871 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
872 i = nextIndex;
874 else
875 i+=write_dir;
878 return *pcGlyphs;
880 return GSUB_E_NOFEATURE;
883 static VOID GPOS_apply_feature(ScriptCache *psc, LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, const SCRIPT_ANALYSIS *analysis, INT* piAdvance, LoadedFeature *feature, const WORD *glyphs, INT glyph_count, GOFFSET *pGoffset)
885 int i;
887 TRACE("%i lookups\n", feature->lookup_count);
888 for (i = 0; i < feature->lookup_count; i++)
890 int j;
891 for (j = 0; j < glyph_count; )
892 j = OpenType_apply_GPOS_lookup(psc, lpotm, lplogfont, analysis, piAdvance, feature->lookups[i], glyphs, j, glyph_count, pGoffset);
896 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
898 OPENTYPE_TAG tag;
899 HRESULT hr;
900 int count = 0;
902 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
904 return(SUCCEEDED(hr));
907 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
909 int i;
910 for (i = *pcGlyphs; i>=index; i--)
911 pwGlyphs[i+1] = pwGlyphs[i];
912 pwGlyphs[index] = glyph;
913 *pcGlyphs = *pcGlyphs+1;
914 if (write_dir < 0)
915 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
916 else
917 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
920 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)
922 CHAR *context_type;
923 int i,g;
924 WCHAR invalid = 0x25cc;
925 WORD invalid_glyph;
927 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
929 /* Mark invalid combinations */
930 for (i = 0; i < cChars; i++)
931 context_type[i] = lex(pwcChars[i]);
933 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
934 for (i = 1, g=1; i < cChars - 1; i++, g++)
936 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
938 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
939 g++;
943 HeapFree(GetProcessHeap(),0,context_type);
946 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
948 int i;
949 for (i=0; i < cChars; i++)
951 switch (pwcChars[i])
953 case 0x000D: pwOutGlyphs[i] = psc->sfp.wgBlank; break;
954 default:
955 if (pwcChars[i] < 0x1C)
956 pwOutGlyphs[i] = psc->sfp.wgDefault;
957 else
958 pwOutGlyphs[i] = psc->sfp.wgBlank;
963 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
965 if (i + delta < 0)
966 return 0;
967 if ( i+ delta >= cchLen)
968 return 0;
970 i += delta;
972 return chars[i];
975 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
977 if (i + delta < 0)
979 if (psa->fLinkBefore)
980 return jtR;
981 else
982 return jtU;
984 if ( i+ delta >= cchLen)
986 if (psa->fLinkAfter)
987 return jtL;
988 else
989 return jtU;
992 i += delta;
994 if (context_type[i] == jtT)
995 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
996 else
997 return context_type[i];
1000 static inline BOOL right_join_causing(CHAR joining_type)
1002 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1005 static inline BOOL left_join_causing(CHAR joining_type)
1007 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1010 static inline BOOL word_break_causing(WCHAR chr)
1012 /* we are working within a string of characters already guareented to
1013 be within one script, Syriac, so we do not worry about any character
1014 other than the space character outside of that range */
1015 return (chr == 0 || chr == 0x20 );
1018 static int combining_lexical_Arabic(WCHAR c)
1020 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1022 switch(c)
1024 case 0x064B:
1025 case 0x064C:
1026 case 0x064E:
1027 case 0x064F:
1028 case 0x0652:
1029 case 0x0657:
1030 case 0x0658:
1031 case 0x06E1: return Arab_DIAC1;
1032 case 0x064D:
1033 case 0x0650:
1034 case 0x0656: return Arab_DIAC2;
1035 case 0x0651: return Arab_DIAC3;
1036 case 0x0610:
1037 case 0x0611:
1038 case 0x0612:
1039 case 0x0613:
1040 case 0x0614:
1041 case 0x0659:
1042 case 0x06D6:
1043 case 0x06DC:
1044 case 0x06DF:
1045 case 0x06E0:
1046 case 0x06E2:
1047 case 0x06E4:
1048 case 0x06E7:
1049 case 0x06E8:
1050 case 0x06EB:
1051 case 0x06EC: return Arab_DIAC4;
1052 case 0x06E3:
1053 case 0x06EA:
1054 case 0x06ED: return Arab_DIAC5;
1055 case 0x0670: return Arab_DIAC6;
1056 case 0x0653: return Arab_DIAC7;
1057 case 0x0655:
1058 case 0x0654: return Arab_DIAC8;
1059 default: return Arab_Norm;
1064 * ContextualShape_Arabic
1066 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1068 CHAR *context_type;
1069 INT *context_shape;
1070 INT dirR, dirL;
1071 int i;
1073 if (*pcGlyphs != cChars)
1075 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1076 return;
1079 if (!psa->fLogicalOrder && psa->fRTL)
1081 dirR = 1;
1082 dirL = -1;
1084 else
1086 dirR = -1;
1087 dirL = 1;
1090 load_ot_tables(hdc, psc);
1092 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1093 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1095 for (i = 0; i < cChars; i++)
1096 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1098 for (i = 0; i < cChars; i++)
1100 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1101 context_shape[i] = Xr;
1102 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1103 context_shape[i] = Xl;
1104 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)))
1105 context_shape[i] = Xm;
1106 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1107 context_shape[i] = Xr;
1108 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1109 context_shape[i] = Xl;
1110 else
1111 context_shape[i] = Xn;
1114 /* Contextual Shaping */
1115 i = 0;
1116 while(i < *pcGlyphs)
1118 BOOL shaped = FALSE;
1120 if (psc->GSUB_Table)
1122 INT nextIndex;
1123 INT prevCount = *pcGlyphs;
1124 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1125 if (nextIndex > GSUB_E_NOGLYPH)
1127 i = nextIndex;
1128 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1130 shaped = (nextIndex > GSUB_E_NOGLYPH);
1133 if (!shaped)
1135 if (context_shape[i] == Xn)
1137 WORD newGlyph = pwOutGlyphs[i];
1138 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1140 /* fall back to presentation form B */
1141 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1142 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1143 pwOutGlyphs[i] = newGlyph;
1146 i++;
1150 HeapFree(GetProcessHeap(),0,context_shape);
1151 HeapFree(GetProcessHeap(),0,context_type);
1153 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1156 static int combining_lexical_Hebrew(WCHAR c)
1158 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};
1160 switch(c)
1162 case 0x05B0:
1163 case 0x05B1:
1164 case 0x05B2:
1165 case 0x05B3:
1166 case 0x05B4:
1167 case 0x05B5:
1168 case 0x05B6:
1169 case 0x05BB: return Hebr_DIAC;
1170 case 0x0599:
1171 case 0x05A1:
1172 case 0x05A9:
1173 case 0x05AE: return Hebr_CANT1;
1174 case 0x0597:
1175 case 0x05A8:
1176 case 0x05AC: return Hebr_CANT2;
1177 case 0x0592:
1178 case 0x0593:
1179 case 0x0594:
1180 case 0x0595:
1181 case 0x05A7:
1182 case 0x05AB: return Hebr_CANT3;
1183 case 0x0598:
1184 case 0x059C:
1185 case 0x059E:
1186 case 0x059F: return Hebr_CANT4;
1187 case 0x059D:
1188 case 0x05A0: return Hebr_CANT5;
1189 case 0x059B:
1190 case 0x05A5: return Hebr_CANT6;
1191 case 0x0591:
1192 case 0x05A3:
1193 case 0x05A6: return Hebr_CANT7;
1194 case 0x0596:
1195 case 0x05A4:
1196 case 0x05AA: return Hebr_CANT8;
1197 case 0x059A:
1198 case 0x05AD: return Hebr_CANT9;
1199 case 0x05AF: return Hebr_CANT10;
1200 case 0x05BC: return Hebr_DAGESH;
1201 case 0x05C4: return Hebr_DOTABV;
1202 case 0x05B9: return Hebr_HOLAM;
1203 case 0x05BD: return Hebr_METEG;
1204 case 0x05B7: return Hebr_PATAH;
1205 case 0x05B8: return Hebr_QAMATS;
1206 case 0x05BF: return Hebr_RAFE;
1207 case 0x05C1:
1208 case 0x05C2: return Hebr_SHINSIN;
1209 default: return Hebr_Norm;
1213 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1215 INT dirL;
1217 if (*pcGlyphs != cChars)
1219 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1220 return;
1223 if (!psa->fLogicalOrder && psa->fRTL)
1224 dirL = -1;
1225 else
1226 dirL = 1;
1228 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1232 * ContextualShape_Syriac
1235 static int combining_lexical_Syriac(WCHAR c)
1237 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};
1239 switch(c)
1241 case 0x730:
1242 case 0x733:
1243 case 0x736:
1244 case 0x73A:
1245 case 0x73D: return Syriac_DIAC1;
1246 case 0x731:
1247 case 0x734:
1248 case 0x737:
1249 case 0x73B:
1250 case 0x73E: return Syriac_DIAC2;
1251 case 0x740:
1252 case 0x749:
1253 case 0x74A: return Syriac_DIAC3;
1254 case 0x732:
1255 case 0x735:
1256 case 0x73F: return Syriac_DIAC4;
1257 case 0x738:
1258 case 0x739:
1259 case 0x73C: return Syriac_DIAC5;
1260 case 0x741:
1261 case 0x30A: return Syriac_DIAC6;
1262 case 0x742:
1263 case 0x325: return Syriac_DIAC7;
1264 case 0x747:
1265 case 0x303: return Syriac_DIAC8;
1266 case 0x748:
1267 case 0x32D:
1268 case 0x32E:
1269 case 0x330:
1270 case 0x331: return Syriac_DIAC9;
1271 case 0x308: return Syriac_DIAC10;
1272 case 0x304: return Syriac_DIAC11;
1273 case 0x307: return Syriac_DIAC12;
1274 case 0x323: return Syriac_DIAC13;
1275 case 0x743: return Syriac_DIAC14;
1276 case 0x744: return Syriac_DIAC15;
1277 case 0x745: return Syriac_DIAC16;
1278 case 0x746: return Syriac_DIAC17;
1279 default: return Syriac_Norm;
1283 #define ALAPH 0x710
1284 #define DALATH 0x715
1285 #define RISH 0x72A
1287 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1289 CHAR *context_type;
1290 INT *context_shape;
1291 INT dirR, dirL;
1292 int i;
1294 if (*pcGlyphs != cChars)
1296 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1297 return;
1300 if (!psa->fLogicalOrder && psa->fRTL)
1302 dirR = 1;
1303 dirL = -1;
1305 else
1307 dirR = -1;
1308 dirL = 1;
1311 load_ot_tables(hdc, psc);
1313 if (!psc->GSUB_Table)
1314 return;
1316 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1317 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1319 for (i = 0; i < cChars; i++)
1320 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1322 for (i = 0; i < cChars; i++)
1324 if (pwcChars[i] == ALAPH)
1326 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1328 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1329 context_shape[i] = Afj;
1330 else if ( rchar != DALATH && rchar != RISH &&
1331 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1332 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1333 context_shape[i] = Afn;
1334 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1335 context_shape[i] = Afx;
1336 else
1337 context_shape[i] = Xn;
1339 else if (context_type[i] == jtR &&
1340 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1341 context_shape[i] = Xr;
1342 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1343 context_shape[i] = Xl;
1344 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)))
1345 context_shape[i] = Xm;
1346 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1347 context_shape[i] = Xr;
1348 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1349 context_shape[i] = Xl;
1350 else
1351 context_shape[i] = Xn;
1354 /* Contextual Shaping */
1355 i = 0;
1356 while(i < *pcGlyphs)
1358 INT nextIndex;
1359 INT prevCount = *pcGlyphs;
1360 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1361 if (nextIndex > GSUB_E_NOGLYPH)
1363 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1364 i = nextIndex;
1366 else
1367 i++;
1370 HeapFree(GetProcessHeap(),0,context_shape);
1371 HeapFree(GetProcessHeap(),0,context_type);
1373 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1376 static int combining_lexical_Thaana(WCHAR c)
1378 enum {Thaana_Norm=0, Thaana_FILI};
1380 switch(c)
1382 case 0x7A6:
1383 case 0x7A7:
1384 case 0x7A8:
1385 case 0x7A9:
1386 case 0x7AA:
1387 case 0x7AB:
1388 case 0x7AC:
1389 case 0x7AD:
1390 case 0x7AE:
1391 case 0x7AF: return Thaana_FILI;
1392 default: return Thaana_Norm;
1396 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1398 INT dirL;
1400 if (*pcGlyphs != cChars)
1402 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1403 return;
1406 if (!psa->fLogicalOrder && psa->fRTL)
1407 dirL = -1;
1408 else
1409 dirL = 1;
1411 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1415 * ContextualShape_Phags_pa
1418 #define phags_pa_CANDRABINDU 0xA873
1419 #define phags_pa_START 0xA840
1420 #define phags_pa_END 0xA87F
1422 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1424 INT *context_shape;
1425 INT dirR, dirL;
1426 int i;
1428 if (*pcGlyphs != cChars)
1430 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1431 return;
1434 if (!psa->fLogicalOrder && psa->fRTL)
1436 dirR = 1;
1437 dirL = -1;
1439 else
1441 dirR = -1;
1442 dirL = 1;
1445 load_ot_tables(hdc, psc);
1447 if (!psc->GSUB_Table)
1448 return;
1450 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1452 for (i = 0; i < cChars; i++)
1454 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1456 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1457 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1458 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1459 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1461 if (jrchar && jlchar)
1462 context_shape[i] = Xm;
1463 else if (jrchar)
1464 context_shape[i] = Xr;
1465 else if (jlchar)
1466 context_shape[i] = Xl;
1467 else
1468 context_shape[i] = Xn;
1470 else
1471 context_shape[i] = -1;
1474 /* Contextual Shaping */
1475 i = 0;
1476 while(i < *pcGlyphs)
1478 if (context_shape[i] >= 0)
1480 INT nextIndex;
1481 INT prevCount = *pcGlyphs;
1482 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1483 if (nextIndex > GSUB_E_NOGLYPH)
1485 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1486 i = nextIndex;
1488 else
1489 i++;
1491 else
1492 i++;
1495 HeapFree(GetProcessHeap(),0,context_shape);
1498 static int combining_lexical_Thai(WCHAR c)
1500 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1502 switch(c)
1504 case 0xE31:
1505 case 0xE34:
1506 case 0xE35:
1507 case 0xE36:
1508 case 0xE37: return Thai_ABOVE1;
1509 case 0xE47:
1510 case 0xE4D: return Thai_ABOVE2;
1511 case 0xE48:
1512 case 0xE49:
1513 case 0xE4A:
1514 case 0xE4B: return Thai_ABOVE3;
1515 case 0xE4C:
1516 case 0xE4E: return Thai_ABOVE4;
1517 case 0xE38:
1518 case 0xE39: return Thai_BELOW1;
1519 case 0xE3A: return Thai_BELOW2;
1520 case 0xE33: return Thai_AM;
1521 default: return Thai_Norm;
1525 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1527 INT dirL;
1529 if (*pcGlyphs != cChars)
1531 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1532 return;
1535 if (!psa->fLogicalOrder && psa->fRTL)
1536 dirL = -1;
1537 else
1538 dirL = 1;
1540 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1543 static int combining_lexical_Lao(WCHAR c)
1545 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1547 switch(c)
1549 case 0xEB1:
1550 case 0xEB4:
1551 case 0xEB5:
1552 case 0xEB6:
1553 case 0xEB7:
1554 case 0xEBB:
1555 case 0xECD: return Lao_ABOVE1;
1556 case 0xEC8:
1557 case 0xEC9:
1558 case 0xECA:
1559 case 0xECB:
1560 case 0xECC: return Lao_ABOVE2;
1561 case 0xEBC: return Lao_BELOW1;
1562 case 0xEB8:
1563 case 0xEB9: return Lao_BELOW2;
1564 case 0xEB3: return Lao_AM;
1565 default: return Lao_Norm;
1569 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1571 INT dirL;
1573 if (*pcGlyphs != cChars)
1575 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1576 return;
1579 if (!psa->fLogicalOrder && psa->fRTL)
1580 dirL = -1;
1581 else
1582 dirL = 1;
1584 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1587 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1589 int i;
1591 /* Replace */
1592 pwOutChars[cWalk] = replacements[0];
1593 cWalk=cWalk+1;
1595 /* Insert */
1596 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1598 int j;
1599 for (j = *pcChars; j > cWalk; j--)
1600 pwOutChars[j] = pwOutChars[j-1];
1601 *pcChars= *pcChars+1;
1602 pwOutChars[cWalk] = replacements[i];
1603 cWalk = cWalk+1;
1607 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1609 int i;
1610 int cWalk;
1612 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1614 for (i = 0; vowels[i].base != 0x0; i++)
1616 if (pwOutChars[cWalk] == vowels[i].base)
1618 int o = 0;
1619 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1620 if (vowels[i].parts[1]) { cWalk++; o++; }
1621 if (vowels[i].parts[2]) { cWalk++; o++; }
1622 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1623 break;
1629 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1631 int i;
1632 int offset = 0;
1633 int cWalk;
1635 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1637 for (i = 0; consonants[i].output!= 0x0; i++)
1639 int j;
1640 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1641 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1642 break;
1644 if (consonants[i].parts[j]==0x0) /* matched all */
1646 int k;
1647 j--;
1648 pwOutChars[cWalk] = consonants[i].output;
1649 for(k = cWalk+1; k < *pcChars - j; k++)
1650 pwOutChars[k] = pwOutChars[k+j];
1651 *pcChars = *pcChars - j;
1652 for (k = j ; k > 0; k--)
1653 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1654 offset += j;
1655 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1656 pwLogClust[k]--;
1657 break;
1660 cWalk++;
1664 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1666 if (s->ralf >= 0)
1668 int j;
1669 WORD Ra = pwChar[s->start];
1670 WORD H = pwChar[s->start+1];
1672 TRACE("Doing reorder of Ra to %i\n",s->base);
1673 for (j = s->start; j < s->base-1; j++)
1674 pwChar[j] = pwChar[j+2];
1675 pwChar[s->base-1] = Ra;
1676 pwChar[s->base] = H;
1678 s->ralf = s->base-1;
1679 s->base -= 2;
1683 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1685 if (s->ralf >= 0)
1687 int j,loc;
1688 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1689 WORD Ra = pwChar[s->start];
1690 WORD H = pwChar[s->start+1];
1691 for (loc = s->end; loc > stop; loc--)
1692 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1693 break;
1695 TRACE("Doing reorder of Ra to %i\n",loc);
1696 for (j = s->start; j < loc-1; j++)
1697 pwChar[j] = pwChar[j+2];
1698 pwChar[loc-1] = Ra;
1699 pwChar[loc] = H;
1701 s->ralf = loc-1;
1702 s->base -= 2;
1703 if (s->blwf >= 0) s->blwf -= 2;
1704 if (s->pref >= 0) s->pref -= 2;
1708 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1710 if (s->ralf >= 0)
1712 int j;
1713 WORD Ra = pwChar[s->start];
1714 WORD H = pwChar[s->start+1];
1716 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1717 for (j = s->start; j < s->end-1; j++)
1718 pwChar[j] = pwChar[j+2];
1719 pwChar[s->end-1] = Ra;
1720 pwChar[s->end] = H;
1722 s->ralf = s->end-1;
1723 s->base -= 2;
1724 if (s->blwf >= 0) s->blwf -= 2;
1725 if (s->pref >= 0) s->pref -= 2;
1729 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1731 int i;
1733 /* reorder Matras */
1734 if (s->end > s->base)
1736 for (i = 1; i <= s->end-s->base; i++)
1738 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1740 int j;
1741 WCHAR c = pwChar[s->base+i];
1742 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1743 for (j = s->base+i; j > s->base; j--)
1744 pwChar[j] = pwChar[j-1];
1745 pwChar[s->base] = c;
1747 if (s->ralf >= s->base) s->ralf++;
1748 if (s->blwf >= s->base) s->blwf++;
1749 if (s->pref >= s->base) s->pref++;
1750 s->base ++;
1756 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1758 int i;
1760 /* reorder Matras */
1761 if (s->end > s->base)
1763 for (i = 1; i <= s->end-s->base; i++)
1765 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1767 int j;
1768 WCHAR c = pwChar[s->base+i];
1769 TRACE("Doing reorder of %x to %i\n",c,s->start);
1770 for (j = s->base+i; j > s->start; j--)
1771 pwChar[j] = pwChar[j-1];
1772 pwChar[s->start] = c;
1774 if (s->ralf >= 0) s->ralf++;
1775 if (s->blwf >= 0) s->blwf++;
1776 if (s->pref >= 0) s->pref++;
1777 s->base ++;
1783 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1785 if (s->blwf >= 0 && g->blwf > g->base)
1787 int j,loc;
1788 int g_offset;
1789 for (loc = s->end; loc > s->blwf; loc--)
1790 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1791 break;
1793 g_offset = (loc - s->blwf) - 1;
1795 if (loc != s->blwf)
1797 WORD blwf = glyphs[g->blwf];
1798 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1799 /* do not care about the pwChar array anymore, just the glyphs */
1800 for (j = 0; j < g_offset; j++)
1801 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1802 glyphs[g->blwf + g_offset] = blwf;
1807 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1809 int i;
1811 /* reorder previously moved Matras to correct position*/
1812 for (i = s->start; i < s->base; i++)
1814 if (lexical(pwChar[i]) == lex_Matra_pre)
1816 int j;
1817 int g_start = g->start + i - s->start;
1818 if (g_start < g->base -1 )
1820 WCHAR og = glyphs[g_start];
1821 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1822 for (j = g_start; j < g->base-1; j++)
1823 glyphs[j] = glyphs[j+1];
1824 glyphs[g->base-1] = og;
1830 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1832 if (s->pref >= 0 && g->pref > g->base)
1834 int j;
1835 WCHAR og = glyphs[g->pref];
1836 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1837 for (j = g->pref; j > g->base; j--)
1838 glyphs[j] = glyphs[j-1];
1839 glyphs[g->base] = og;
1843 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1845 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1846 if (s->start == s->base && s->base == s->end) return;
1847 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1849 Reorder_Ra_follows_base(pwChar, s, lexical);
1850 Reorder_Matra_precede_base(pwChar, s, lexical);
1853 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1855 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1856 if (s->start == s->base && s->base == s->end) return;
1857 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1859 Reorder_Ra_follows_matra(pwChar, s, lexical);
1860 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1863 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1865 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1866 if (s->start == s->base && s->base == s->end) return;
1867 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1869 Reorder_Ra_follows_base(pwChar, s, lexical);
1870 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1873 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1875 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1876 if (s->start == s->base && s->base == s->end) return;
1877 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1879 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1880 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1883 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1885 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1886 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1887 if (s->start == s->base && s->base == s->end) return;
1888 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1890 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1893 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1895 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1896 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1897 if (s->start == s->base && s->base == s->end) return;
1898 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1900 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1901 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1905 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1907 if (shift == 0)
1908 return;
1910 if (glyph_index->start > index)
1911 glyph_index->start += shift;
1912 if (glyph_index->base > index)
1913 glyph_index->base+= shift;
1914 if (glyph_index->end > index)
1915 glyph_index->end+= shift;
1916 if (glyph_index->ralf > index)
1917 glyph_index->ralf+= shift;
1918 if (glyph_index->blwf > index)
1919 glyph_index->blwf+= shift;
1920 if (glyph_index->pref > index)
1921 glyph_index->pref+= shift;
1924 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 )
1926 int index = glyph_index->start;
1928 if (!feature)
1929 return;
1931 while(index <= glyph_index->end)
1933 INT nextIndex;
1934 INT prevCount = *pcGlyphs;
1935 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1936 if (nextIndex > GSUB_E_NOGLYPH)
1938 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1939 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1940 index = nextIndex;
1942 else
1943 index++;
1947 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1949 int i = 0;
1950 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)))))
1951 i++;
1952 if (index + i <= end-1)
1953 return index + i;
1954 else
1955 return -1;
1958 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)
1960 INT index, nextIndex;
1961 INT count,g_offset;
1963 count = syllable->base - syllable->start;
1965 g_offset = 0;
1966 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1967 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1969 INT prevCount = *pcGlyphs;
1970 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1971 if (nextIndex > GSUB_E_NOGLYPH)
1973 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1974 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1975 g_offset += (*pcGlyphs - prevCount);
1978 index+=2;
1979 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1983 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)
1985 INT nextIndex;
1986 INT prevCount = *pcGlyphs;
1988 if (syllable->ralf >= 0)
1990 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1991 if (nextIndex > GSUB_E_NOGLYPH)
1993 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1994 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1999 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2001 int i = 0;
2002 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2003 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2004 is_consonant(lexical(pwChars[index+i+1])))))
2005 i++;
2006 if (index + i <= end-1)
2007 return index+i;
2008 else
2009 return -1;
2012 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)
2014 INT index, nextIndex;
2015 INT count, g_offset=0;
2016 INT ralf = syllable->ralf;
2018 count = syllable->end - syllable->base;
2020 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2022 while (index >= 0)
2024 INT prevCount = *pcGlyphs;
2025 if (ralf >=0 && ralf < index)
2027 g_offset--;
2028 ralf = -1;
2031 if (!modern)
2033 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2034 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2035 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2038 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2039 if (nextIndex > GSUB_E_NOGLYPH)
2041 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2042 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2043 g_offset += (*pcGlyphs - prevCount);
2045 else if (!modern)
2047 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2048 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2049 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2052 index+=2;
2053 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2057 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)
2059 int c;
2060 int overall_shift = 0;
2061 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2062 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2063 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2064 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2065 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2066 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2067 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2068 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2069 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2070 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2071 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2072 IndicSyllable glyph_indexs;
2074 for (c = 0; c < syllable_count; c++)
2076 int old_end;
2077 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2078 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2079 old_end = glyph_indexs.end;
2081 if (locl)
2083 TRACE("applying feature locl\n");
2084 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2086 if (nukt)
2088 TRACE("applying feature nukt\n");
2089 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2091 if (akhn)
2093 TRACE("applying feature akhn\n");
2094 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2097 if (rphf)
2098 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2099 if (rkrf)
2101 TRACE("applying feature rkrf\n");
2102 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2104 if (pref)
2105 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2106 if (blwf)
2108 if (!modern)
2109 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2111 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2114 if (half)
2115 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2116 if (pstf)
2118 TRACE("applying feature pstf\n");
2119 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2121 if (vatu)
2123 TRACE("applying feature vatu\n");
2124 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2126 if (cjct)
2128 TRACE("applying feature cjct\n");
2129 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2132 if (second_reorder)
2133 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2135 overall_shift += glyph_indexs.end - old_end;
2139 static inline int unicode_lex(WCHAR c)
2141 int type;
2143 if (!c) return lex_Generic;
2144 if (c == 0x200D) return lex_ZWJ;
2145 if (c == 0x200C) return lex_ZWNJ;
2146 if (c == 0x00A0) return lex_NBSP;
2148 type = get_table_entry( indic_syllabic_table, c );
2150 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2152 switch( type )
2154 case 0x0d07: /* Unknown */
2155 case 0x0e07: /* Unknwon */
2156 default: return lex_Generic;
2157 case 0x0001:
2158 case 0x0002:
2159 case 0x0011:
2160 case 0x0012:
2161 case 0x0013:
2162 case 0x0014: return lex_Modifier;
2163 case 0x0003:
2164 case 0x0009:
2165 case 0x000a:
2166 case 0x000b:
2167 case 0x000d:
2168 case 0x000e:
2169 case 0x000f:
2170 case 0x0010: return lex_Consonant;
2171 case 0x0004: return lex_Nukta;
2172 case 0x0005: return lex_Halant;
2173 case 0x0006:
2174 case 0x0008: return lex_Vowel;
2175 case 0x0007:
2176 case 0x0107: return lex_Matra_post;
2177 case 0x0207:
2178 case 0x0307: return lex_Matra_pre;
2179 case 0x0807:
2180 case 0x0907:
2181 case 0x0a07:
2182 case 0x0b07:
2183 case 0x0c07:
2184 case 0x0407: return lex_Composed_Vowel;
2185 case 0x0507: return lex_Matra_above;
2186 case 0x0607: return lex_Matra_below;
2187 case 0x000c:
2188 case 0x0015: return lex_Ra;
2192 static int sinhala_lex(WCHAR c)
2194 switch (c)
2196 case 0x0DDA:
2197 case 0x0DDD:
2198 case 0x0DDC:
2199 case 0x0DDE: return lex_Matra_post;
2200 default:
2201 return unicode_lex(c);
2205 static const VowelComponents Sinhala_vowels[] = {
2206 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2207 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2208 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2209 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2210 {0x0000, {0x0000,0x0000,0x0}}};
2212 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2214 int cCount = cChars;
2215 int i;
2216 WCHAR *input;
2217 IndicSyllable *syllables = NULL;
2218 int syllable_count = 0;
2220 if (*pcGlyphs != cChars)
2222 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2223 return;
2226 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2228 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2230 /* Step 1: Decompose multi part vowels */
2231 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2233 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2235 /* Step 2: Reorder within Syllables */
2236 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2237 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2239 /* Step 3: Strip dangling joiners */
2240 for (i = 0; i < cCount; i++)
2242 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2243 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2244 input[i] = 0x0020;
2247 /* Step 4: Base Form application to syllables */
2248 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2249 *pcGlyphs = cCount;
2250 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2252 HeapFree(GetProcessHeap(),0,input);
2253 HeapFree(GetProcessHeap(),0,syllables);
2256 static int devanagari_lex(WCHAR c)
2258 switch (c)
2260 case 0x0930: return lex_Ra;
2261 default:
2262 return unicode_lex(c);
2266 static const ConsonantComponents Devanagari_consonants[] ={
2267 {{0x0928, 0x093C, 0x00000}, 0x0929},
2268 {{0x0930, 0x093C, 0x00000}, 0x0931},
2269 {{0x0933, 0x093C, 0x00000}, 0x0934},
2270 {{0x0915, 0x093C, 0x00000}, 0x0958},
2271 {{0x0916, 0x093C, 0x00000}, 0x0959},
2272 {{0x0917, 0x093C, 0x00000}, 0x095A},
2273 {{0x091C, 0x093C, 0x00000}, 0x095B},
2274 {{0x0921, 0x093C, 0x00000}, 0x095C},
2275 {{0x0922, 0x093C, 0x00000}, 0x095D},
2276 {{0x092B, 0x093C, 0x00000}, 0x095E},
2277 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2279 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2281 int cCount = cChars;
2282 WCHAR *input;
2283 IndicSyllable *syllables = NULL;
2284 int syllable_count = 0;
2285 BOOL modern = get_GSUB_Indic2(psa, psc);
2287 if (*pcGlyphs != cChars)
2289 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2290 return;
2293 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2294 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2296 /* Step 1: Compose Consonant and Nukta */
2297 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2298 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2300 /* Step 2: Reorder within Syllables */
2301 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2302 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2303 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2304 *pcGlyphs = cCount;
2306 /* Step 3: Base Form application to syllables */
2307 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2309 HeapFree(GetProcessHeap(),0,input);
2310 HeapFree(GetProcessHeap(),0,syllables);
2313 static int bengali_lex(WCHAR c)
2315 switch (c)
2317 case 0x09B0: return lex_Ra;
2318 default:
2319 return unicode_lex(c);
2323 static const VowelComponents Bengali_vowels[] = {
2324 {0x09CB, {0x09C7,0x09BE,0x0000}},
2325 {0x09CC, {0x09C7,0x09D7,0x0000}},
2326 {0x0000, {0x0000,0x0000,0x0000}}};
2328 static const ConsonantComponents Bengali_consonants[] = {
2329 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2330 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2331 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2332 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2333 {{0x0000,0x0000,0x0000}, 0x0000}};
2335 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2337 int cCount = cChars;
2338 WCHAR *input;
2339 IndicSyllable *syllables = NULL;
2340 int syllable_count = 0;
2341 BOOL modern = get_GSUB_Indic2(psa, psc);
2343 if (*pcGlyphs != cChars)
2345 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2346 return;
2349 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2350 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2352 /* Step 1: Decompose Vowels and Compose Consonants */
2353 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2354 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2355 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2357 /* Step 2: Reorder within Syllables */
2358 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2359 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2360 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2361 *pcGlyphs = cCount;
2363 /* Step 3: Initial form is only applied to the beginning of words */
2364 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2366 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2368 int index = cCount;
2369 int gCount = 1;
2370 if (index > 0) index++;
2372 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2376 /* Step 4: Base Form application to syllables */
2377 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2379 HeapFree(GetProcessHeap(),0,input);
2380 HeapFree(GetProcessHeap(),0,syllables);
2383 static int gurmukhi_lex(WCHAR c)
2385 if (c == 0x0A71)
2386 return lex_Modifier;
2387 else
2388 return unicode_lex(c);
2391 static const ConsonantComponents Gurmukhi_consonants[] = {
2392 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2393 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2394 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2395 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2396 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2397 {{0x0000,0x0000,0x0000}, 0x0000}};
2399 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2401 int cCount = cChars;
2402 WCHAR *input;
2403 IndicSyllable *syllables = NULL;
2404 int syllable_count = 0;
2405 BOOL modern = get_GSUB_Indic2(psa, psc);
2407 if (*pcGlyphs != cChars)
2409 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2410 return;
2413 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2414 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2416 /* Step 1: Compose Consonants */
2417 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2418 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2420 /* Step 2: Reorder within Syllables */
2421 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2422 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2423 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2424 *pcGlyphs = cCount;
2426 /* Step 3: Base Form application to syllables */
2427 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2429 HeapFree(GetProcessHeap(),0,input);
2430 HeapFree(GetProcessHeap(),0,syllables);
2433 static int gujarati_lex(WCHAR c)
2435 switch (c)
2437 case 0x0AB0: return lex_Ra;
2438 default:
2439 return unicode_lex(c);
2443 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2445 int cCount = cChars;
2446 WCHAR *input;
2447 IndicSyllable *syllables = NULL;
2448 int syllable_count = 0;
2449 BOOL modern = get_GSUB_Indic2(psa, psc);
2451 if (*pcGlyphs != cChars)
2453 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2454 return;
2457 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2458 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2460 /* Step 1: Reorder within Syllables */
2461 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2462 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2463 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2464 *pcGlyphs = cCount;
2466 /* Step 2: Base Form application to syllables */
2467 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2469 HeapFree(GetProcessHeap(),0,input);
2470 HeapFree(GetProcessHeap(),0,syllables);
2473 static int oriya_lex(WCHAR c)
2475 switch (c)
2477 case 0x0B30: return lex_Ra;
2478 default:
2479 return unicode_lex(c);
2483 static const VowelComponents Oriya_vowels[] = {
2484 {0x0B48, {0x0B47,0x0B56,0x0000}},
2485 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2486 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2487 {0x0000, {0x0000,0x0000,0x0000}}};
2489 static const ConsonantComponents Oriya_consonants[] = {
2490 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2491 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2492 {{0x0000,0x0000,0x0000}, 0x0000}};
2494 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2496 int cCount = cChars;
2497 WCHAR *input;
2498 IndicSyllable *syllables = NULL;
2499 int syllable_count = 0;
2500 BOOL modern = get_GSUB_Indic2(psa, psc);
2502 if (*pcGlyphs != cChars)
2504 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2505 return;
2508 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2509 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2511 /* Step 1: Decompose Vowels and Compose Consonants */
2512 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2513 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2514 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2516 /* Step 2: Reorder within Syllables */
2517 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2518 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2519 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2520 *pcGlyphs = cCount;
2522 /* Step 3: Base Form application to syllables */
2523 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2525 HeapFree(GetProcessHeap(),0,input);
2526 HeapFree(GetProcessHeap(),0,syllables);
2529 static int tamil_lex(WCHAR c)
2531 return unicode_lex(c);
2534 static const VowelComponents Tamil_vowels[] = {
2535 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2536 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2537 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2538 {0x0000, {0x0000,0x0000,0x0000}}};
2540 static const ConsonantComponents Tamil_consonants[] = {
2541 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2542 {{0x0000,0x0000,0x0000}, 0x0000}};
2544 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2546 int cCount = cChars;
2547 WCHAR *input;
2548 IndicSyllable *syllables = NULL;
2549 int syllable_count = 0;
2550 BOOL modern = get_GSUB_Indic2(psa, psc);
2552 if (*pcGlyphs != cChars)
2554 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2555 return;
2558 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2559 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2561 /* Step 1: Decompose Vowels and Compose Consonants */
2562 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2563 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2564 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2566 /* Step 2: Reorder within Syllables */
2567 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2568 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2569 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2570 *pcGlyphs = cCount;
2572 /* Step 3: Base Form application to syllables */
2573 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2575 HeapFree(GetProcessHeap(),0,input);
2576 HeapFree(GetProcessHeap(),0,syllables);
2579 static int telugu_lex(WCHAR c)
2581 switch (c)
2583 case 0x0C43:
2584 case 0x0C44: return lex_Modifier;
2585 default:
2586 return unicode_lex(c);
2590 static const VowelComponents Telugu_vowels[] = {
2591 {0x0C48, {0x0C46,0x0C56,0x0000}},
2592 {0x0000, {0x0000,0x0000,0x0000}}};
2594 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2596 int cCount = cChars;
2597 WCHAR *input;
2598 IndicSyllable *syllables = NULL;
2599 int syllable_count = 0;
2600 BOOL modern = get_GSUB_Indic2(psa, psc);
2602 if (*pcGlyphs != cChars)
2604 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2605 return;
2608 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2609 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2611 /* Step 1: Decompose Vowels */
2612 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2613 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2615 /* Step 2: Reorder within Syllables */
2616 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2617 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2618 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2619 *pcGlyphs = cCount;
2621 /* Step 3: Base Form application to syllables */
2622 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2624 HeapFree(GetProcessHeap(),0,input);
2625 HeapFree(GetProcessHeap(),0,syllables);
2628 static int kannada_lex(WCHAR c)
2630 switch (c)
2632 case 0x0CB0: return lex_Ra;
2633 default:
2634 return unicode_lex(c);
2638 static const VowelComponents Kannada_vowels[] = {
2639 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2640 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2641 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2642 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2643 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2644 {0x0000, {0x0000,0x0000,0x0000}}};
2646 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2648 int cCount = cChars;
2649 WCHAR *input;
2650 IndicSyllable *syllables = NULL;
2651 int syllable_count = 0;
2652 BOOL modern = get_GSUB_Indic2(psa, psc);
2654 if (*pcGlyphs != cChars)
2656 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2657 return;
2660 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2661 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2663 /* Step 1: Decompose Vowels */
2664 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2665 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2667 /* Step 2: Reorder within Syllables */
2668 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2669 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2670 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2671 *pcGlyphs = cCount;
2673 /* Step 3: Base Form application to syllables */
2674 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2676 HeapFree(GetProcessHeap(),0,input);
2677 HeapFree(GetProcessHeap(),0,syllables);
2680 static int malayalam_lex(WCHAR c)
2682 return unicode_lex(c);
2685 static const VowelComponents Malayalam_vowels[] = {
2686 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2687 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2688 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2689 {0x0000, {0x0000,0x0000,0x0000}}};
2691 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2693 int cCount = cChars;
2694 WCHAR *input;
2695 IndicSyllable *syllables = NULL;
2696 int syllable_count = 0;
2697 BOOL modern = get_GSUB_Indic2(psa, psc);
2699 if (*pcGlyphs != cChars)
2701 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2702 return;
2705 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2706 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2708 /* Step 1: Decompose Vowels */
2709 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2710 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2712 /* Step 2: Reorder within Syllables */
2713 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2714 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2715 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2716 *pcGlyphs = cCount;
2718 /* Step 3: Base Form application to syllables */
2719 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2721 HeapFree(GetProcessHeap(),0,input);
2722 HeapFree(GetProcessHeap(),0,syllables);
2725 static int khmer_lex(WCHAR c)
2727 return unicode_lex(c);
2730 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2732 int cCount = cChars;
2733 WCHAR *input;
2734 IndicSyllable *syllables = NULL;
2735 int syllable_count = 0;
2737 if (*pcGlyphs != cChars)
2739 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2740 return;
2743 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2744 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2746 /* Step 1: Reorder within Syllables */
2747 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2748 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2749 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2750 *pcGlyphs = cCount;
2752 /* Step 2: Base Form application to syllables */
2753 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2755 HeapFree(GetProcessHeap(),0,input);
2756 HeapFree(GetProcessHeap(),0,syllables);
2759 static inline BOOL mongolian_wordbreak(WCHAR chr)
2761 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2764 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2766 INT *context_shape;
2767 INT dirL;
2768 int i;
2770 if (*pcGlyphs != cChars)
2772 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2773 return;
2776 if (!psa->fLogicalOrder && psa->fRTL)
2777 dirL = -1;
2778 else
2779 dirL = 1;
2781 if (!psc->GSUB_Table)
2782 return;
2784 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2786 for (i = 0; i < cChars; i++)
2788 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2790 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2791 context_shape[i] = Xn;
2792 else
2793 context_shape[i] = Xl;
2795 else
2797 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2798 context_shape[i] = Xr;
2799 else
2800 context_shape[i] = Xm;
2804 /* Contextual Shaping */
2805 i = 0;
2806 while(i < *pcGlyphs)
2808 INT nextIndex;
2809 INT prevCount = *pcGlyphs;
2810 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2811 if (nextIndex > GSUB_E_NOGLYPH)
2813 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2814 i = nextIndex;
2816 else
2817 i++;
2820 HeapFree(GetProcessHeap(),0,context_shape);
2823 static void ShapeCharGlyphProp_Default( 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)
2825 int i,k;
2827 for (i = 0; i < cGlyphs; i++)
2829 int char_index[20];
2830 int char_count = 0;
2832 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2833 if (k>=0)
2835 for (; k < cChars && pwLogClust[k] == i; k++)
2836 char_index[char_count++] = k;
2839 if (char_count == 0)
2840 continue;
2842 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2844 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2845 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2847 else
2848 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2851 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2852 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2855 static void ShapeCharGlyphProp_Latin( 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 )
2857 int i;
2859 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2861 for (i = 0; i < cGlyphs; i++)
2862 if (pGlyphProp[i].sva.fZeroWidth)
2863 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2866 static void ShapeCharGlyphProp_Control( 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 )
2868 int i;
2869 for (i = 0; i < cGlyphs; i++)
2871 pGlyphProp[i].sva.fClusterStart = 1;
2872 pGlyphProp[i].sva.fDiacritic = 0;
2873 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2875 if (pwGlyphs[i] == psc->sfp.wgDefault)
2876 pGlyphProp[i].sva.fZeroWidth = 0;
2877 else
2878 pGlyphProp[i].sva.fZeroWidth = 1;
2882 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 )
2884 int i,k;
2885 int initGlyph, finaGlyph;
2886 INT dirR, dirL;
2887 BYTE *spaces;
2889 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2890 memset(spaces,0,cGlyphs);
2892 if (!psa->fLogicalOrder && psa->fRTL)
2894 initGlyph = cGlyphs-1;
2895 finaGlyph = 0;
2896 dirR = 1;
2897 dirL = -1;
2899 else
2901 initGlyph = 0;
2902 finaGlyph = cGlyphs-1;
2903 dirR = -1;
2904 dirL = 1;
2907 for (i = 0; i < cGlyphs; i++)
2909 for (k = 0; k < cChars; k++)
2910 if (pwLogClust[k] == i)
2912 if (pwcChars[k] == 0x0020)
2913 spaces[i] = 1;
2917 for (i = 0; i < cGlyphs; i++)
2919 int char_index[20];
2920 int char_count = 0;
2921 BOOL isInit, isFinal;
2923 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2924 if (k>=0)
2926 for (; k < cChars && pwLogClust[k] == i; k++)
2927 char_index[char_count++] = k;
2930 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2931 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2933 if (char_count == 0)
2934 continue;
2936 if (char_count == 1)
2938 if (pwcChars[char_index[0]] == 0x0020) /* space */
2940 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2941 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2943 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2944 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2945 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2947 if (!isInit && !isFinal)
2948 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2949 else if (isInit)
2950 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2951 else
2952 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2954 else if (!isInit)
2956 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2957 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2958 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2959 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2960 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2961 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2962 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2963 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2964 else
2965 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2967 else if (!isInit && !isFinal)
2968 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2969 else
2970 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2972 else if (char_count == 2)
2974 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2975 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2976 else if (!isInit)
2977 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2978 else
2979 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2981 else if (!isInit && !isFinal)
2982 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2983 else
2984 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2987 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2988 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2989 HeapFree(GetProcessHeap(),0,spaces);
2992 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 )
2994 int i,k;
2996 for (i = 0; i < cGlyphs; i++)
2998 int char_index[20];
2999 int char_count = 0;
3001 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3002 if (k>=0)
3004 for (; k < cChars && pwLogClust[k] == i; k++)
3005 char_index[char_count++] = k;
3008 if (char_count == 0)
3009 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3010 else
3012 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3013 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3014 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3018 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3019 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3022 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 )
3024 int i;
3025 int finaGlyph;
3026 INT dirL;
3028 if (!psa->fLogicalOrder && psa->fRTL)
3030 finaGlyph = 0;
3031 dirL = -1;
3033 else
3035 finaGlyph = cGlyphs-1;
3036 dirL = 1;
3039 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3041 for (i = 0; i < cGlyphs; i++)
3043 int k;
3044 int char_index[20];
3045 int char_count = 0;
3047 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3048 if (k>=0)
3050 for (; k < cChars && pwLogClust[k] == i; k++)
3051 char_index[char_count++] = k;
3054 if (i == finaGlyph)
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3056 else
3057 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3059 if (char_count == 0)
3060 continue;
3062 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3063 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3065 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3066 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3067 pGlyphProp[i].sva.fClusterStart = 0;
3070 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3072 /* Do not allow justification between marks and their base */
3073 for (i = 0; i < cGlyphs; i++)
3075 if (!pGlyphProp[i].sva.fClusterStart)
3076 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3080 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)
3082 int i,k;
3084 for (i = 0; i < cGlyphs; i++)
3086 int char_index[20];
3087 int char_count = 0;
3089 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3090 if (k>=0)
3092 for (; k < cChars && pwLogClust[k] == i; k++)
3093 char_index[char_count++] = k;
3096 if (char_count == 0)
3097 continue;
3099 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3101 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3102 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3104 else
3105 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3107 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3108 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3111 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)
3113 int i,k;
3115 for (i = 0; i < cGlyphs; i++)
3117 int char_index[20];
3118 int char_count = 0;
3120 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3121 if (k>=0)
3123 for (; k < cChars && pwLogClust[k] == i; k++)
3124 char_index[char_count++] = k;
3127 if (char_count == 0)
3128 continue;
3130 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3132 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3133 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3135 else
3136 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3138 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3139 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3141 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3142 for (i = 0; i < cGlyphs; i++)
3144 if (!pGlyphProp[i].sva.fClusterStart)
3146 pGlyphProp[i].sva.fDiacritic = 0;
3147 pGlyphProp[i].sva.fZeroWidth = 0;
3152 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)
3154 int i,k;
3156 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3157 for (i = 0; i < cGlyphs; i++)
3159 int char_index[20];
3160 int char_count = 0;
3162 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3163 if (k>=0)
3165 for (; k < cChars && pwLogClust[k] == i; k++)
3166 char_index[char_count++] = k;
3169 if (override_gsub)
3171 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3172 pGlyphProp[i].sva.fDiacritic = FALSE;
3173 pGlyphProp[i].sva.fZeroWidth = FALSE;
3176 if (char_count == 0)
3178 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3179 continue;
3182 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3184 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3185 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3187 else
3188 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3190 pGlyphProp[i].sva.fClusterStart = 0;
3191 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3192 switch (lexical(pwcChars[char_index[k]]))
3194 case lex_Matra_pre:
3195 case lex_Matra_post:
3196 case lex_Matra_above:
3197 case lex_Matra_below:
3198 case lex_Modifier:
3199 case lex_Halant:
3200 break;
3201 case lex_ZWJ:
3202 case lex_ZWNJ:
3203 /* check for dangling joiners */
3204 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3205 pGlyphProp[i].sva.fClusterStart = 1;
3206 else
3207 k = char_count;
3208 break;
3209 default:
3210 pGlyphProp[i].sva.fClusterStart = 1;
3211 break;
3215 if (use_syllables)
3217 IndicSyllable *syllables = NULL;
3218 int syllable_count = 0;
3219 BOOL modern = get_GSUB_Indic2(psa, psc);
3221 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3223 for (i = 0; i < syllable_count; i++)
3225 int j;
3226 WORD g = pwLogClust[syllables[i].start];
3227 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3229 if (pwLogClust[j] != g)
3231 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3232 pwLogClust[j] = g;
3237 HeapFree(GetProcessHeap(), 0, syllables);
3240 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3243 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 )
3245 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3248 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 )
3250 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3253 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 )
3255 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3258 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 )
3260 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3263 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 )
3265 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3268 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 )
3270 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3273 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 )
3275 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3278 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 )
3280 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3283 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 )
3285 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3288 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 )
3290 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3293 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 )
3295 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3298 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)
3300 load_ot_tables(hdc, psc);
3302 if (ShapingData[psa->eScript].charGlyphPropProc)
3303 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3304 else
3305 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3308 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3310 load_ot_tables(hdc, psc);
3312 if (ShapingData[psa->eScript].contextProc)
3313 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3316 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)
3318 int i;
3319 INT dirL;
3321 if (!rpRangeProperties)
3322 return;
3324 load_ot_tables(hdc, psc);
3326 if (!psc->GSUB_Table)
3327 return;
3329 if (!psa->fLogicalOrder && psa->fRTL)
3330 dirL = -1;
3331 else
3332 dirL = 1;
3334 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3336 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3337 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3341 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3343 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3344 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3346 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3349 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3351 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3352 int i;
3354 rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3356 if (!rpRangeProperties)
3357 return;
3359 load_ot_tables(hdc, psc);
3361 if (!psc->GPOS_Table || !psc->otm)
3362 return;
3364 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3366 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3368 LoadedFeature *feature;
3370 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3371 if (!feature)
3372 continue;
3374 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3379 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3381 LoadedFeature *feature;
3382 int i;
3384 if (!ShapingData[psa->eScript].requiredFeatures)
3385 return S_OK;
3387 load_ot_tables(hdc, psc);
3389 /* we need to have at least one of the required features */
3390 i = 0;
3391 while (ShapingData[psa->eScript].requiredFeatures[i])
3393 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3394 if (feature)
3395 return S_OK;
3396 i++;
3399 return USP_E_SCRIPT_NOT_IN_FONT;
3402 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3403 SCRIPT_ANALYSIS *psa, int cMaxTags,
3404 OPENTYPE_TAG *pScriptTags, int *pcTags)
3406 HRESULT hr;
3407 OPENTYPE_TAG searching = 0x00000000;
3409 load_ot_tables(hdc, psc);
3411 if (psa && scriptInformation[psa->eScript].scriptTag)
3412 searching = scriptInformation[psa->eScript].scriptTag;
3414 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3415 if (FAILED(hr))
3416 *pcTags = 0;
3417 return hr;
3420 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3421 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3422 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3423 int *pcTags)
3425 HRESULT hr;
3426 OPENTYPE_TAG searching = 0x00000000;
3427 BOOL fellback = FALSE;
3429 load_ot_tables(hdc, psc);
3431 if (psa && psc->userLang != 0)
3432 searching = psc->userLang;
3434 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3435 if (FAILED(hr))
3437 fellback = TRUE;
3438 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3441 if (FAILED(hr) || fellback)
3442 *pcTags = 0;
3443 if (SUCCEEDED(hr) && fellback && psa)
3444 hr = E_INVALIDARG;
3445 return hr;
3448 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3449 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3450 OPENTYPE_TAG tagLangSys, int cMaxTags,
3451 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3453 HRESULT hr;
3454 BOOL filter = FALSE;
3456 load_ot_tables(hdc, psc);
3458 if (psa && scriptInformation[psa->eScript].scriptTag)
3460 FIXME("Filtering not implemented\n");
3461 filter = TRUE;
3464 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3466 if (FAILED(hr))
3467 *pcTags = 0;
3468 return hr;