d3d9/tests: Fix pixel shader version check in test_pointsize().
[wine.git] / dlls / usp10 / shape.c
blob9d07e5b002ed172fbdc57daa06b1d990397deb52
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[] DECLSPEC_HIDDEN;
88 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
89 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
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 *const 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 *const 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 *const 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 *const required_lao_features[] =
268 "ccmp",
269 NULL
272 static const char *const 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 *const 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 *const 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 *const 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 *const 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 *const 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 *const 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 *const *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 cluster_dir = pwLogClust[0] < pwLogClust[chars-1] ? 1 : -1;
755 int i;
756 int target_glyph = nextIndex - write_dir;
757 int target_index = -1;
758 int replacing_glyph = -1;
759 int changed = 0;
761 if (changeCount > 0)
763 if (write_dir > 0)
764 target_glyph = nextIndex - changeCount;
765 else
766 target_glyph = nextIndex + (changeCount + 1);
769 target_index = USP10_FindGlyphInLogClust(pwLogClust, chars, target_glyph);
770 if (target_index == -1)
772 ERR("Unable to find target glyph\n");
773 return;
776 if (changeCount < 0)
778 /* merge glyphs */
779 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
781 if (pwLogClust[i] == target_glyph)
782 continue;
783 if(pwLogClust[i] == replacing_glyph)
784 pwLogClust[i] = target_glyph;
785 else
787 changed--;
788 if (changed >= changeCount)
790 replacing_glyph = pwLogClust[i];
791 pwLogClust[i] = target_glyph;
793 else
794 break;
798 /* renumber trailing indexes */
799 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
801 if (pwLogClust[i] != target_glyph)
802 pwLogClust[i] += changeCount;
805 else
807 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
808 pwLogClust[i] += changeCount;
813 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 )
815 if (psc->GSUB_Table)
817 LoadedFeature *feature;
818 int lookup_index;
820 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
821 if (!feature)
822 return GSUB_E_NOFEATURE;
824 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
825 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
827 int i;
829 if (write_dir > 0)
830 i = 0;
831 else
832 i = *pcGlyphs-1;
833 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
834 while(i < *pcGlyphs && i >= 0)
836 INT nextIndex;
837 INT prevCount = *pcGlyphs;
839 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
840 if (*pcGlyphs != prevCount)
842 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
843 i = nextIndex;
845 else
846 i+=write_dir;
849 return *pcGlyphs;
851 return GSUB_E_NOFEATURE;
854 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)
856 int dir = analysis->fLogicalOrder && analysis->fRTL ? -1 : 1;
857 unsigned int start_idx, i, j;
859 TRACE("%i lookups\n", feature->lookup_count);
861 start_idx = dir < 0 ? glyph_count - 1 : 0;
862 for (i = 0; i < feature->lookup_count; i++)
864 for (j = 0; j < glyph_count; )
865 j += OpenType_apply_GPOS_lookup(psc, lpotm, lplogfont, analysis, piAdvance,
866 feature->lookups[i], glyphs, start_idx + dir * j, glyph_count, pGoffset);
870 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
872 OPENTYPE_TAG tag;
873 HRESULT hr;
874 int count = 0;
876 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
878 return(SUCCEEDED(hr));
881 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
883 int i;
884 for (i = *pcGlyphs; i>=index; i--)
885 pwGlyphs[i+1] = pwGlyphs[i];
886 pwGlyphs[index] = glyph;
887 *pcGlyphs = *pcGlyphs+1;
888 if (write_dir < 0)
889 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
890 else
891 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
894 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)
896 CHAR *context_type;
897 int i,g;
898 WCHAR invalid = 0x25cc;
899 WORD invalid_glyph;
901 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
903 /* Mark invalid combinations */
904 for (i = 0; i < cChars; i++)
905 context_type[i] = lex(pwcChars[i]);
907 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
908 for (i = 1, g=1; i < cChars - 1; i++, g++)
910 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
912 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
913 g++;
917 HeapFree(GetProcessHeap(),0,context_type);
920 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
922 int i;
923 for (i=0; i < cChars; i++)
925 switch (pwcChars[i])
927 case 0x000A:
928 case 0x000D:
929 pwOutGlyphs[i] = psc->sfp.wgBlank;
930 break;
931 default:
932 if (pwcChars[i] < 0x1C)
933 pwOutGlyphs[i] = psc->sfp.wgDefault;
934 else
935 pwOutGlyphs[i] = psc->sfp.wgBlank;
940 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
942 if (i + delta < 0)
943 return 0;
944 if ( i+ delta >= cchLen)
945 return 0;
947 i += delta;
949 return chars[i];
952 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
954 if (i + delta < 0)
956 if (psa->fLinkBefore)
957 return jtR;
958 else
959 return jtU;
961 if ( i+ delta >= cchLen)
963 if (psa->fLinkAfter)
964 return jtL;
965 else
966 return jtU;
969 i += delta;
971 if (context_type[i] == jtT)
972 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
973 else
974 return context_type[i];
977 static inline BOOL right_join_causing(CHAR joining_type)
979 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
982 static inline BOOL left_join_causing(CHAR joining_type)
984 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
987 static inline BOOL word_break_causing(WCHAR chr)
989 /* we are working within a string of characters already guareented to
990 be within one script, Syriac, so we do not worry about any character
991 other than the space character outside of that range */
992 return (chr == 0 || chr == 0x20 );
995 static int combining_lexical_Arabic(WCHAR c)
997 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
999 switch(c)
1001 case 0x064B:
1002 case 0x064C:
1003 case 0x064E:
1004 case 0x064F:
1005 case 0x0652:
1006 case 0x0657:
1007 case 0x0658:
1008 case 0x06E1: return Arab_DIAC1;
1009 case 0x064D:
1010 case 0x0650:
1011 case 0x0656: return Arab_DIAC2;
1012 case 0x0651: return Arab_DIAC3;
1013 case 0x0610:
1014 case 0x0611:
1015 case 0x0612:
1016 case 0x0613:
1017 case 0x0614:
1018 case 0x0659:
1019 case 0x06D6:
1020 case 0x06DC:
1021 case 0x06DF:
1022 case 0x06E0:
1023 case 0x06E2:
1024 case 0x06E4:
1025 case 0x06E7:
1026 case 0x06E8:
1027 case 0x06EB:
1028 case 0x06EC: return Arab_DIAC4;
1029 case 0x06E3:
1030 case 0x06EA:
1031 case 0x06ED: return Arab_DIAC5;
1032 case 0x0670: return Arab_DIAC6;
1033 case 0x0653: return Arab_DIAC7;
1034 case 0x0655:
1035 case 0x0654: return Arab_DIAC8;
1036 default: return Arab_Norm;
1041 * ContextualShape_Arabic
1043 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1045 CHAR *context_type;
1046 INT *context_shape;
1047 INT dirR, dirL;
1048 int i;
1049 int char_index;
1050 int glyph_index;
1052 if (*pcGlyphs != cChars)
1054 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1055 return;
1058 if (psa->fLogicalOrder && psa->fRTL)
1060 dirR = -1;
1061 dirL = 1;
1063 else
1065 dirR = 1;
1066 dirL = -1;
1069 load_ot_tables(hdc, psc);
1071 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1072 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1074 for (i = 0; i < cChars; i++)
1075 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1077 for (i = 0; i < cChars; i++)
1079 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1080 context_shape[i] = Xr;
1081 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1082 context_shape[i] = Xl;
1083 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)))
1084 context_shape[i] = Xm;
1085 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1086 context_shape[i] = Xr;
1087 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1088 context_shape[i] = Xl;
1089 else
1090 context_shape[i] = Xn;
1093 /* Contextual Shaping */
1094 if (dirL > 0)
1095 char_index = glyph_index = 0;
1096 else
1097 char_index = glyph_index = cChars-1;
1099 while(char_index < cChars && char_index >= 0)
1101 BOOL shaped = FALSE;
1103 if (psc->GSUB_Table)
1105 INT nextIndex, offset = 0;
1106 INT prevCount = *pcGlyphs;
1108 /* Apply CCMP first */
1109 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1111 if (prevCount != *pcGlyphs)
1113 offset = *pcGlyphs - prevCount;
1114 if (dirL < 0)
1115 glyph_index -= offset * dirL;
1118 /* Apply the contextual feature */
1119 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1121 if (nextIndex > GSUB_E_NOGLYPH)
1123 UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1124 char_index += dirL;
1125 if (!offset)
1126 glyph_index = nextIndex;
1127 else
1129 offset = *pcGlyphs - prevCount;
1130 glyph_index += dirL * (offset + 1);
1132 shaped = TRUE;
1134 else if (nextIndex == GSUB_E_NOGLYPH)
1136 char_index += dirL;
1137 glyph_index += dirL;
1138 shaped = TRUE;
1142 if (!shaped)
1144 if (context_shape[char_index] == Xn)
1146 WORD newGlyph = pwOutGlyphs[glyph_index];
1147 if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
1149 /* fall back to presentation form B */
1150 WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
1151 if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1152 pwOutGlyphs[glyph_index] = newGlyph;
1155 char_index += dirL;
1156 glyph_index += dirL;
1160 HeapFree(GetProcessHeap(),0,context_shape);
1161 HeapFree(GetProcessHeap(),0,context_type);
1163 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1166 static int combining_lexical_Hebrew(WCHAR c)
1168 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};
1170 switch(c)
1172 case 0x05B0:
1173 case 0x05B1:
1174 case 0x05B2:
1175 case 0x05B3:
1176 case 0x05B4:
1177 case 0x05B5:
1178 case 0x05B6:
1179 case 0x05BB: return Hebr_DIAC;
1180 case 0x0599:
1181 case 0x05A1:
1182 case 0x05A9:
1183 case 0x05AE: return Hebr_CANT1;
1184 case 0x0597:
1185 case 0x05A8:
1186 case 0x05AC: return Hebr_CANT2;
1187 case 0x0592:
1188 case 0x0593:
1189 case 0x0594:
1190 case 0x0595:
1191 case 0x05A7:
1192 case 0x05AB: return Hebr_CANT3;
1193 case 0x0598:
1194 case 0x059C:
1195 case 0x059E:
1196 case 0x059F: return Hebr_CANT4;
1197 case 0x059D:
1198 case 0x05A0: return Hebr_CANT5;
1199 case 0x059B:
1200 case 0x05A5: return Hebr_CANT6;
1201 case 0x0591:
1202 case 0x05A3:
1203 case 0x05A6: return Hebr_CANT7;
1204 case 0x0596:
1205 case 0x05A4:
1206 case 0x05AA: return Hebr_CANT8;
1207 case 0x059A:
1208 case 0x05AD: return Hebr_CANT9;
1209 case 0x05AF: return Hebr_CANT10;
1210 case 0x05BC: return Hebr_DAGESH;
1211 case 0x05C4: return Hebr_DOTABV;
1212 case 0x05B9: return Hebr_HOLAM;
1213 case 0x05BD: return Hebr_METEG;
1214 case 0x05B7: return Hebr_PATAH;
1215 case 0x05B8: return Hebr_QAMATS;
1216 case 0x05BF: return Hebr_RAFE;
1217 case 0x05C1:
1218 case 0x05C2: return Hebr_SHINSIN;
1219 default: return Hebr_Norm;
1223 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1225 INT dirL;
1227 if (*pcGlyphs != cChars)
1229 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1230 return;
1233 if (!psa->fLogicalOrder && psa->fRTL)
1234 dirL = -1;
1235 else
1236 dirL = 1;
1238 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1242 * ContextualShape_Syriac
1245 static int combining_lexical_Syriac(WCHAR c)
1247 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};
1249 switch(c)
1251 case 0x730:
1252 case 0x733:
1253 case 0x736:
1254 case 0x73A:
1255 case 0x73D: return Syriac_DIAC1;
1256 case 0x731:
1257 case 0x734:
1258 case 0x737:
1259 case 0x73B:
1260 case 0x73E: return Syriac_DIAC2;
1261 case 0x740:
1262 case 0x749:
1263 case 0x74A: return Syriac_DIAC3;
1264 case 0x732:
1265 case 0x735:
1266 case 0x73F: return Syriac_DIAC4;
1267 case 0x738:
1268 case 0x739:
1269 case 0x73C: return Syriac_DIAC5;
1270 case 0x741:
1271 case 0x30A: return Syriac_DIAC6;
1272 case 0x742:
1273 case 0x325: return Syriac_DIAC7;
1274 case 0x747:
1275 case 0x303: return Syriac_DIAC8;
1276 case 0x748:
1277 case 0x32D:
1278 case 0x32E:
1279 case 0x330:
1280 case 0x331: return Syriac_DIAC9;
1281 case 0x308: return Syriac_DIAC10;
1282 case 0x304: return Syriac_DIAC11;
1283 case 0x307: return Syriac_DIAC12;
1284 case 0x323: return Syriac_DIAC13;
1285 case 0x743: return Syriac_DIAC14;
1286 case 0x744: return Syriac_DIAC15;
1287 case 0x745: return Syriac_DIAC16;
1288 case 0x746: return Syriac_DIAC17;
1289 default: return Syriac_Norm;
1293 #define ALAPH 0x710
1294 #define DALATH 0x715
1295 #define RISH 0x72A
1297 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1299 CHAR *context_type;
1300 INT *context_shape;
1301 INT dirR, dirL;
1302 int i;
1303 int char_index;
1304 int glyph_index;
1306 if (*pcGlyphs != cChars)
1308 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1309 return;
1312 if (!psa->fLogicalOrder && psa->fRTL)
1314 dirR = 1;
1315 dirL = -1;
1317 else
1319 dirR = -1;
1320 dirL = 1;
1323 load_ot_tables(hdc, psc);
1325 if (!psc->GSUB_Table)
1326 return;
1328 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1329 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1331 for (i = 0; i < cChars; i++)
1332 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1334 for (i = 0; i < cChars; i++)
1336 if (pwcChars[i] == ALAPH)
1338 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1340 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1341 context_shape[i] = Afj;
1342 else if ( rchar != DALATH && rchar != RISH &&
1343 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1344 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1345 context_shape[i] = Afn;
1346 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1347 context_shape[i] = Afx;
1348 else
1349 context_shape[i] = Xn;
1351 else if (context_type[i] == jtR &&
1352 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1353 context_shape[i] = Xr;
1354 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1355 context_shape[i] = Xl;
1356 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)))
1357 context_shape[i] = Xm;
1358 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1359 context_shape[i] = Xr;
1360 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1361 context_shape[i] = Xl;
1362 else
1363 context_shape[i] = Xn;
1366 /* Contextual Shaping */
1367 if (dirL > 0)
1368 char_index = glyph_index = 0;
1369 else
1370 char_index = glyph_index = cChars-1;
1372 while(char_index < cChars && char_index >= 0)
1374 INT nextIndex, offset = 0;
1375 INT prevCount = *pcGlyphs;
1377 /* Apply CCMP first */
1378 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1380 if (prevCount != *pcGlyphs)
1382 offset = *pcGlyphs - prevCount;
1383 if (dirL < 0)
1384 glyph_index -= offset * dirL;
1387 /* Apply the contextual feature */
1388 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1389 if (nextIndex > GSUB_E_NOGLYPH)
1391 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1392 char_index += dirL;
1393 if (!offset)
1394 glyph_index = nextIndex;
1395 else
1397 offset = *pcGlyphs - prevCount;
1398 glyph_index += dirL * (offset + 1);
1401 else
1403 char_index += dirL;
1404 glyph_index += dirL;
1408 HeapFree(GetProcessHeap(),0,context_shape);
1409 HeapFree(GetProcessHeap(),0,context_type);
1411 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1414 static int combining_lexical_Thaana(WCHAR c)
1416 enum {Thaana_Norm=0, Thaana_FILI};
1418 switch(c)
1420 case 0x7A6:
1421 case 0x7A7:
1422 case 0x7A8:
1423 case 0x7A9:
1424 case 0x7AA:
1425 case 0x7AB:
1426 case 0x7AC:
1427 case 0x7AD:
1428 case 0x7AE:
1429 case 0x7AF: return Thaana_FILI;
1430 default: return Thaana_Norm;
1434 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1436 INT dirL;
1438 if (*pcGlyphs != cChars)
1440 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1441 return;
1444 if (!psa->fLogicalOrder && psa->fRTL)
1445 dirL = -1;
1446 else
1447 dirL = 1;
1449 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1453 * ContextualShape_Phags_pa
1456 #define phags_pa_CANDRABINDU 0xA873
1457 #define phags_pa_START 0xA840
1458 #define phags_pa_END 0xA87F
1460 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1462 INT *context_shape;
1463 INT dirR, dirL;
1464 int i;
1465 int char_index;
1466 int glyph_index;
1468 if (*pcGlyphs != cChars)
1470 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1471 return;
1474 if (!psa->fLogicalOrder && psa->fRTL)
1476 dirR = 1;
1477 dirL = -1;
1479 else
1481 dirR = -1;
1482 dirL = 1;
1485 load_ot_tables(hdc, psc);
1487 if (!psc->GSUB_Table)
1488 return;
1490 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1492 for (i = 0; i < cChars; i++)
1494 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1496 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1497 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1498 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1499 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1501 if (jrchar && jlchar)
1502 context_shape[i] = Xm;
1503 else if (jrchar)
1504 context_shape[i] = Xr;
1505 else if (jlchar)
1506 context_shape[i] = Xl;
1507 else
1508 context_shape[i] = Xn;
1510 else
1511 context_shape[i] = -1;
1514 /* Contextual Shaping */
1515 if (dirL > 0)
1516 char_index = glyph_index = 0;
1517 else
1518 char_index = glyph_index = cChars-1;
1520 while(char_index < cChars && char_index >= 0)
1522 if (context_shape[char_index] >= 0)
1524 INT nextIndex;
1525 INT prevCount = *pcGlyphs;
1526 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1528 if (nextIndex > GSUB_E_NOGLYPH)
1530 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1531 glyph_index = nextIndex;
1532 char_index += dirL;
1534 else
1536 char_index += dirL;
1537 glyph_index += dirL;
1540 else
1542 char_index += dirL;
1543 glyph_index += dirL;
1547 HeapFree(GetProcessHeap(),0,context_shape);
1550 static int combining_lexical_Thai(WCHAR c)
1552 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1554 switch(c)
1556 case 0xE31:
1557 case 0xE34:
1558 case 0xE35:
1559 case 0xE36:
1560 case 0xE37: return Thai_ABOVE1;
1561 case 0xE47:
1562 case 0xE4D: return Thai_ABOVE2;
1563 case 0xE48:
1564 case 0xE49:
1565 case 0xE4A:
1566 case 0xE4B: return Thai_ABOVE3;
1567 case 0xE4C:
1568 case 0xE4E: return Thai_ABOVE4;
1569 case 0xE38:
1570 case 0xE39: return Thai_BELOW1;
1571 case 0xE3A: return Thai_BELOW2;
1572 case 0xE33: return Thai_AM;
1573 default: return Thai_Norm;
1577 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1579 INT dirL;
1581 if (*pcGlyphs != cChars)
1583 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1584 return;
1587 if (!psa->fLogicalOrder && psa->fRTL)
1588 dirL = -1;
1589 else
1590 dirL = 1;
1592 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1595 static int combining_lexical_Lao(WCHAR c)
1597 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1599 switch(c)
1601 case 0xEB1:
1602 case 0xEB4:
1603 case 0xEB5:
1604 case 0xEB6:
1605 case 0xEB7:
1606 case 0xEBB:
1607 case 0xECD: return Lao_ABOVE1;
1608 case 0xEC8:
1609 case 0xEC9:
1610 case 0xECA:
1611 case 0xECB:
1612 case 0xECC: return Lao_ABOVE2;
1613 case 0xEBC: return Lao_BELOW1;
1614 case 0xEB8:
1615 case 0xEB9: return Lao_BELOW2;
1616 case 0xEB3: return Lao_AM;
1617 default: return Lao_Norm;
1621 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1623 INT dirL;
1625 if (*pcGlyphs != cChars)
1627 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1628 return;
1631 if (!psa->fLogicalOrder && psa->fRTL)
1632 dirL = -1;
1633 else
1634 dirL = 1;
1636 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1639 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1641 int i;
1643 /* Replace */
1644 pwOutChars[cWalk] = replacements[0];
1645 cWalk=cWalk+1;
1647 /* Insert */
1648 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1650 int j;
1651 for (j = *pcChars; j > cWalk; j--)
1652 pwOutChars[j] = pwOutChars[j-1];
1653 *pcChars= *pcChars+1;
1654 pwOutChars[cWalk] = replacements[i];
1655 cWalk = cWalk+1;
1659 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1661 int i;
1662 int cWalk;
1664 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1666 for (i = 0; vowels[i].base != 0x0; i++)
1668 if (pwOutChars[cWalk] == vowels[i].base)
1670 int o = 0;
1671 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1672 if (vowels[i].parts[1]) { cWalk++; o++; }
1673 if (vowels[i].parts[2]) { cWalk++; o++; }
1674 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1675 break;
1681 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1683 int i;
1684 int offset = 0;
1685 int cWalk;
1687 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1689 for (i = 0; consonants[i].output!= 0x0; i++)
1691 int j;
1692 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1693 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1694 break;
1696 if (consonants[i].parts[j]==0x0) /* matched all */
1698 int k;
1699 j--;
1700 pwOutChars[cWalk] = consonants[i].output;
1701 for(k = cWalk+1; k < *pcChars - j; k++)
1702 pwOutChars[k] = pwOutChars[k+j];
1703 *pcChars = *pcChars - j;
1704 for (k = j ; k > 0; k--)
1705 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1706 offset += j;
1707 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1708 pwLogClust[k]--;
1709 break;
1712 cWalk++;
1716 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1718 if (s->ralf >= 0)
1720 int j;
1721 WORD Ra = pwChar[s->start];
1722 WORD H = pwChar[s->start+1];
1724 TRACE("Doing reorder of Ra to %i\n",s->base);
1725 for (j = s->start; j < s->base-1; j++)
1726 pwChar[j] = pwChar[j+2];
1727 pwChar[s->base-1] = Ra;
1728 pwChar[s->base] = H;
1730 s->ralf = s->base-1;
1731 s->base -= 2;
1735 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1737 if (s->ralf >= 0)
1739 int j,loc;
1740 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1741 WORD Ra = pwChar[s->start];
1742 WORD H = pwChar[s->start+1];
1743 for (loc = s->end; loc > stop; loc--)
1744 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1745 break;
1747 TRACE("Doing reorder of Ra to %i\n",loc);
1748 for (j = s->start; j < loc-1; j++)
1749 pwChar[j] = pwChar[j+2];
1750 pwChar[loc-1] = Ra;
1751 pwChar[loc] = H;
1753 s->ralf = loc-1;
1754 s->base -= 2;
1755 if (s->blwf >= 0) s->blwf -= 2;
1756 if (s->pref >= 0) s->pref -= 2;
1760 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1762 if (s->ralf >= 0)
1764 int j;
1765 WORD Ra = pwChar[s->start];
1766 WORD H = pwChar[s->start+1];
1768 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1769 for (j = s->start; j < s->end-1; j++)
1770 pwChar[j] = pwChar[j+2];
1771 pwChar[s->end-1] = Ra;
1772 pwChar[s->end] = H;
1774 s->ralf = s->end-1;
1775 s->base -= 2;
1776 if (s->blwf >= 0) s->blwf -= 2;
1777 if (s->pref >= 0) s->pref -= 2;
1781 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1783 int i;
1785 /* reorder Matras */
1786 if (s->end > s->base)
1788 for (i = 1; i <= s->end-s->base; i++)
1790 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1792 int j;
1793 WCHAR c = pwChar[s->base+i];
1794 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1795 for (j = s->base+i; j > s->base; j--)
1796 pwChar[j] = pwChar[j-1];
1797 pwChar[s->base] = c;
1799 if (s->ralf >= s->base) s->ralf++;
1800 if (s->blwf >= s->base) s->blwf++;
1801 if (s->pref >= s->base) s->pref++;
1802 s->base ++;
1808 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1810 int i;
1812 /* reorder Matras */
1813 if (s->end > s->base)
1815 for (i = 1; i <= s->end-s->base; i++)
1817 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1819 int j;
1820 WCHAR c = pwChar[s->base+i];
1821 TRACE("Doing reorder of %x to %i\n",c,s->start);
1822 for (j = s->base+i; j > s->start; j--)
1823 pwChar[j] = pwChar[j-1];
1824 pwChar[s->start] = c;
1826 if (s->ralf >= 0) s->ralf++;
1827 if (s->blwf >= 0) s->blwf++;
1828 if (s->pref >= 0) s->pref++;
1829 s->base ++;
1835 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1837 if (s->blwf >= 0 && g->blwf > g->base)
1839 int j,loc;
1840 int g_offset;
1841 for (loc = s->end; loc > s->blwf; loc--)
1842 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1843 break;
1845 g_offset = (loc - s->blwf) - 1;
1847 if (loc != s->blwf)
1849 WORD blwf = glyphs[g->blwf];
1850 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1851 /* do not care about the pwChar array anymore, just the glyphs */
1852 for (j = 0; j < g_offset; j++)
1853 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1854 glyphs[g->blwf + g_offset] = blwf;
1859 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1861 int i;
1863 /* reorder previously moved Matras to correct position*/
1864 for (i = s->start; i < s->base; i++)
1866 if (lexical(pwChar[i]) == lex_Matra_pre)
1868 int j;
1869 int g_start = g->start + i - s->start;
1870 if (g_start < g->base -1 )
1872 WCHAR og = glyphs[g_start];
1873 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1874 for (j = g_start; j < g->base-1; j++)
1875 glyphs[j] = glyphs[j+1];
1876 glyphs[g->base-1] = og;
1882 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1884 if (s->pref >= 0 && g->pref > g->base)
1886 int j;
1887 WCHAR og = glyphs[g->pref];
1888 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1889 for (j = g->pref; j > g->base; j--)
1890 glyphs[j] = glyphs[j-1];
1891 glyphs[g->base] = og;
1895 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1897 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1898 if (s->start == s->base && s->base == s->end) return;
1899 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1901 Reorder_Ra_follows_base(pwChar, s, lexical);
1902 Reorder_Matra_precede_base(pwChar, s, lexical);
1905 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1907 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1908 if (s->start == s->base && s->base == s->end) return;
1909 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1911 Reorder_Ra_follows_matra(pwChar, s, lexical);
1912 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1915 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1917 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1918 if (s->start == s->base && s->base == s->end) return;
1919 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1921 Reorder_Ra_follows_base(pwChar, s, lexical);
1922 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1925 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1927 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1928 if (s->start == s->base && s->base == s->end) return;
1929 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1931 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1932 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1935 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1937 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1938 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1939 if (s->start == s->base && s->base == s->end) return;
1940 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1942 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1945 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1947 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1948 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1949 if (s->start == s->base && s->base == s->end) return;
1950 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1952 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1953 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1957 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1959 if (shift == 0)
1960 return;
1962 if (glyph_index->start > index)
1963 glyph_index->start += shift;
1964 if (glyph_index->base > index)
1965 glyph_index->base+= shift;
1966 if (glyph_index->end > index)
1967 glyph_index->end+= shift;
1968 if (glyph_index->ralf > index)
1969 glyph_index->ralf+= shift;
1970 if (glyph_index->blwf > index)
1971 glyph_index->blwf+= shift;
1972 if (glyph_index->pref > index)
1973 glyph_index->pref+= shift;
1976 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 )
1978 int index = glyph_index->start;
1980 if (!feature)
1981 return;
1983 while(index <= glyph_index->end)
1985 INT nextIndex;
1986 INT prevCount = *pcGlyphs;
1987 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1988 if (nextIndex > GSUB_E_NOGLYPH)
1990 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1991 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1992 index = nextIndex;
1994 else
1995 index++;
1999 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2001 int i = 0;
2002 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)))))
2003 i++;
2004 if (index + i <= end-1)
2005 return index + i;
2006 else
2007 return -1;
2010 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)
2012 INT index, nextIndex;
2013 INT count,g_offset;
2015 count = syllable->base - syllable->start;
2017 g_offset = 0;
2018 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2019 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2021 INT prevCount = *pcGlyphs;
2022 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2023 if (nextIndex > GSUB_E_NOGLYPH)
2025 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2026 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2027 g_offset += (*pcGlyphs - prevCount);
2030 index+=2;
2031 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2035 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)
2037 INT nextIndex;
2038 INT prevCount = *pcGlyphs;
2040 if (syllable->ralf >= 0)
2042 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2043 if (nextIndex > GSUB_E_NOGLYPH)
2045 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2046 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2051 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2053 int i = 0;
2054 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2055 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2056 is_consonant(lexical(pwChars[index+i+1])))))
2057 i++;
2058 if (index + i <= end-1)
2059 return index+i;
2060 else
2061 return -1;
2064 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)
2066 INT index, nextIndex;
2067 INT count, g_offset=0;
2068 INT ralf = syllable->ralf;
2070 count = syllable->end - syllable->base;
2072 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2074 while (index >= 0)
2076 INT prevCount = *pcGlyphs;
2077 if (ralf >=0 && ralf < index)
2079 g_offset--;
2080 ralf = -1;
2083 if (!modern)
2085 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2086 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2087 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2090 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2091 if (nextIndex > GSUB_E_NOGLYPH)
2093 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2094 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2095 g_offset += (*pcGlyphs - prevCount);
2097 else if (!modern)
2099 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2100 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2101 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2104 index+=2;
2105 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2109 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)
2111 int c;
2112 int overall_shift = 0;
2113 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2114 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2115 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2116 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2117 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2118 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2119 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2120 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2121 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2122 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2123 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2124 IndicSyllable glyph_indexs;
2126 for (c = 0; c < syllable_count; c++)
2128 int old_end;
2129 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2130 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2131 old_end = glyph_indexs.end;
2133 if (locl)
2135 TRACE("applying feature locl\n");
2136 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2138 if (nukt)
2140 TRACE("applying feature nukt\n");
2141 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2143 if (akhn)
2145 TRACE("applying feature akhn\n");
2146 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2149 if (rphf)
2150 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2151 if (rkrf)
2153 TRACE("applying feature rkrf\n");
2154 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2156 if (pref)
2157 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2158 if (blwf)
2160 if (!modern)
2161 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2163 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2166 if (half)
2167 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2168 if (pstf)
2170 TRACE("applying feature pstf\n");
2171 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2173 if (vatu)
2175 TRACE("applying feature vatu\n");
2176 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2178 if (cjct)
2180 TRACE("applying feature cjct\n");
2181 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2184 if (second_reorder)
2185 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2187 overall_shift += glyph_indexs.end - old_end;
2191 static inline int unicode_lex(WCHAR c)
2193 int type;
2195 if (!c) return lex_Generic;
2196 if (c == 0x200D) return lex_ZWJ;
2197 if (c == 0x200C) return lex_ZWNJ;
2198 if (c == 0x00A0) return lex_NBSP;
2200 type = get_table_entry( indic_syllabic_table, c );
2202 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2204 switch( type )
2206 case 0x0d07: /* Unknown */
2207 case 0x0e07: /* Unknown */
2208 default: return lex_Generic;
2209 case 0x0001:
2210 case 0x0002:
2211 case 0x0011:
2212 case 0x0012:
2213 case 0x0013:
2214 case 0x0014: return lex_Modifier;
2215 case 0x0003:
2216 case 0x0009:
2217 case 0x000a:
2218 case 0x000b:
2219 case 0x000d:
2220 case 0x000e:
2221 case 0x000f:
2222 case 0x0010: return lex_Consonant;
2223 case 0x0004: return lex_Nukta;
2224 case 0x0005: return lex_Halant;
2225 case 0x0006:
2226 case 0x0008: return lex_Vowel;
2227 case 0x0007:
2228 case 0x0107: return lex_Matra_post;
2229 case 0x0207:
2230 case 0x0307: return lex_Matra_pre;
2231 case 0x0807:
2232 case 0x0907:
2233 case 0x0a07:
2234 case 0x0b07:
2235 case 0x0c07:
2236 case 0x0407: return lex_Composed_Vowel;
2237 case 0x0507: return lex_Matra_above;
2238 case 0x0607: return lex_Matra_below;
2239 case 0x000c:
2240 case 0x0015: return lex_Ra;
2244 static int sinhala_lex(WCHAR c)
2246 switch (c)
2248 case 0x0DDA:
2249 case 0x0DDD:
2250 case 0x0DDC:
2251 case 0x0DDE: return lex_Matra_post;
2252 default:
2253 return unicode_lex(c);
2257 static const VowelComponents Sinhala_vowels[] = {
2258 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2259 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2260 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2261 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2262 {0x0000, {0x0000,0x0000,0x0}}};
2264 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2266 int cCount = cChars;
2267 int i;
2268 WCHAR *input;
2269 IndicSyllable *syllables = NULL;
2270 int syllable_count = 0;
2272 if (*pcGlyphs != cChars)
2274 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2275 return;
2278 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2280 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2282 /* Step 1: Decompose multi part vowels */
2283 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2285 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2287 /* Step 2: Reorder within Syllables */
2288 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2289 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2291 /* Step 3: Strip dangling joiners */
2292 for (i = 0; i < cCount; i++)
2294 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2295 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2296 input[i] = 0x0020;
2299 /* Step 4: Base Form application to syllables */
2300 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2301 *pcGlyphs = cCount;
2302 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2304 HeapFree(GetProcessHeap(),0,input);
2305 HeapFree(GetProcessHeap(),0,syllables);
2308 static int devanagari_lex(WCHAR c)
2310 switch (c)
2312 case 0x0930: return lex_Ra;
2313 default:
2314 return unicode_lex(c);
2318 static const ConsonantComponents Devanagari_consonants[] ={
2319 {{0x0928, 0x093C, 0x00000}, 0x0929},
2320 {{0x0930, 0x093C, 0x00000}, 0x0931},
2321 {{0x0933, 0x093C, 0x00000}, 0x0934},
2322 {{0x0915, 0x093C, 0x00000}, 0x0958},
2323 {{0x0916, 0x093C, 0x00000}, 0x0959},
2324 {{0x0917, 0x093C, 0x00000}, 0x095A},
2325 {{0x091C, 0x093C, 0x00000}, 0x095B},
2326 {{0x0921, 0x093C, 0x00000}, 0x095C},
2327 {{0x0922, 0x093C, 0x00000}, 0x095D},
2328 {{0x092B, 0x093C, 0x00000}, 0x095E},
2329 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2331 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2333 int cCount = cChars;
2334 WCHAR *input;
2335 IndicSyllable *syllables = NULL;
2336 int syllable_count = 0;
2337 BOOL modern = get_GSUB_Indic2(psa, psc);
2339 if (*pcGlyphs != cChars)
2341 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2342 return;
2345 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2346 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2348 /* Step 1: Compose Consonant and Nukta */
2349 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2350 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2352 /* Step 2: Reorder within Syllables */
2353 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2354 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2355 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2356 *pcGlyphs = cCount;
2358 /* Step 3: Base Form application to syllables */
2359 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2361 HeapFree(GetProcessHeap(),0,input);
2362 HeapFree(GetProcessHeap(),0,syllables);
2365 static int bengali_lex(WCHAR c)
2367 switch (c)
2369 case 0x09B0: return lex_Ra;
2370 default:
2371 return unicode_lex(c);
2375 static const VowelComponents Bengali_vowels[] = {
2376 {0x09CB, {0x09C7,0x09BE,0x0000}},
2377 {0x09CC, {0x09C7,0x09D7,0x0000}},
2378 {0x0000, {0x0000,0x0000,0x0000}}};
2380 static const ConsonantComponents Bengali_consonants[] = {
2381 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2382 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2383 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2384 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2385 {{0x0000,0x0000,0x0000}, 0x0000}};
2387 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2389 int cCount = cChars;
2390 WCHAR *input;
2391 IndicSyllable *syllables = NULL;
2392 int syllable_count = 0;
2393 BOOL modern = get_GSUB_Indic2(psa, psc);
2395 if (*pcGlyphs != cChars)
2397 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2398 return;
2401 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2402 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2404 /* Step 1: Decompose Vowels and Compose Consonants */
2405 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2406 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2407 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2409 /* Step 2: Reorder within Syllables */
2410 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2411 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2412 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2413 *pcGlyphs = cCount;
2415 /* Step 3: Initial form is only applied to the beginning of words */
2416 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2418 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2420 int index = cCount;
2421 int gCount = 1;
2422 if (index > 0) index++;
2424 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2428 /* Step 4: Base Form application to syllables */
2429 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2431 HeapFree(GetProcessHeap(),0,input);
2432 HeapFree(GetProcessHeap(),0,syllables);
2435 static int gurmukhi_lex(WCHAR c)
2437 if (c == 0x0A71)
2438 return lex_Modifier;
2439 else
2440 return unicode_lex(c);
2443 static const ConsonantComponents Gurmukhi_consonants[] = {
2444 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2445 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2446 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2447 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2448 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2449 {{0x0000,0x0000,0x0000}, 0x0000}};
2451 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2453 int cCount = cChars;
2454 WCHAR *input;
2455 IndicSyllable *syllables = NULL;
2456 int syllable_count = 0;
2457 BOOL modern = get_GSUB_Indic2(psa, psc);
2459 if (*pcGlyphs != cChars)
2461 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2462 return;
2465 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2466 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2468 /* Step 1: Compose Consonants */
2469 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2470 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2472 /* Step 2: Reorder within Syllables */
2473 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2474 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2475 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2476 *pcGlyphs = cCount;
2478 /* Step 3: Base Form application to syllables */
2479 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2481 HeapFree(GetProcessHeap(),0,input);
2482 HeapFree(GetProcessHeap(),0,syllables);
2485 static int gujarati_lex(WCHAR c)
2487 switch (c)
2489 case 0x0AB0: return lex_Ra;
2490 default:
2491 return unicode_lex(c);
2495 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2497 int cCount = cChars;
2498 WCHAR *input;
2499 IndicSyllable *syllables = NULL;
2500 int syllable_count = 0;
2501 BOOL modern = get_GSUB_Indic2(psa, psc);
2503 if (*pcGlyphs != cChars)
2505 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2506 return;
2509 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2510 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2512 /* Step 1: Reorder within Syllables */
2513 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2514 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2515 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2516 *pcGlyphs = cCount;
2518 /* Step 2: Base Form application to syllables */
2519 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2521 HeapFree(GetProcessHeap(),0,input);
2522 HeapFree(GetProcessHeap(),0,syllables);
2525 static int oriya_lex(WCHAR c)
2527 switch (c)
2529 case 0x0B30: return lex_Ra;
2530 default:
2531 return unicode_lex(c);
2535 static const VowelComponents Oriya_vowels[] = {
2536 {0x0B48, {0x0B47,0x0B56,0x0000}},
2537 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2538 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2539 {0x0000, {0x0000,0x0000,0x0000}}};
2541 static const ConsonantComponents Oriya_consonants[] = {
2542 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2543 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2544 {{0x0000,0x0000,0x0000}, 0x0000}};
2546 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2548 int cCount = cChars;
2549 WCHAR *input;
2550 IndicSyllable *syllables = NULL;
2551 int syllable_count = 0;
2552 BOOL modern = get_GSUB_Indic2(psa, psc);
2554 if (*pcGlyphs != cChars)
2556 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2557 return;
2560 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2561 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2563 /* Step 1: Decompose Vowels and Compose Consonants */
2564 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2565 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2566 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2568 /* Step 2: Reorder within Syllables */
2569 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2570 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2571 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2572 *pcGlyphs = cCount;
2574 /* Step 3: Base Form application to syllables */
2575 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2577 HeapFree(GetProcessHeap(),0,input);
2578 HeapFree(GetProcessHeap(),0,syllables);
2581 static int tamil_lex(WCHAR c)
2583 return unicode_lex(c);
2586 static const VowelComponents Tamil_vowels[] = {
2587 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2588 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2589 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2590 {0x0000, {0x0000,0x0000,0x0000}}};
2592 static const ConsonantComponents Tamil_consonants[] = {
2593 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2594 {{0x0000,0x0000,0x0000}, 0x0000}};
2596 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2598 int cCount = cChars;
2599 WCHAR *input;
2600 IndicSyllable *syllables = NULL;
2601 int syllable_count = 0;
2602 BOOL modern = get_GSUB_Indic2(psa, psc);
2604 if (*pcGlyphs != cChars)
2606 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2607 return;
2610 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2611 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2613 /* Step 1: Decompose Vowels and Compose Consonants */
2614 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2615 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2616 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2618 /* Step 2: Reorder within Syllables */
2619 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2620 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2621 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2622 *pcGlyphs = cCount;
2624 /* Step 3: Base Form application to syllables */
2625 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2627 HeapFree(GetProcessHeap(),0,input);
2628 HeapFree(GetProcessHeap(),0,syllables);
2631 static int telugu_lex(WCHAR c)
2633 switch (c)
2635 case 0x0C43:
2636 case 0x0C44: return lex_Modifier;
2637 default:
2638 return unicode_lex(c);
2642 static const VowelComponents Telugu_vowels[] = {
2643 {0x0C48, {0x0C46,0x0C56,0x0000}},
2644 {0x0000, {0x0000,0x0000,0x0000}}};
2646 static void ContextualShape_Telugu(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*2) * sizeof(WCHAR));
2661 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2663 /* Step 1: Decompose Vowels */
2664 DecomposeVowels(hdc, input, &cCount, Telugu_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, telugu_lex, Reorder_Like_Bengali, 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, telugu_lex, SecondReorder_Like_Telugu, modern);
2676 HeapFree(GetProcessHeap(),0,input);
2677 HeapFree(GetProcessHeap(),0,syllables);
2680 static int kannada_lex(WCHAR c)
2682 switch (c)
2684 case 0x0CB0: return lex_Ra;
2685 default:
2686 return unicode_lex(c);
2690 static const VowelComponents Kannada_vowels[] = {
2691 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2692 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2693 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2694 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2695 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2696 {0x0000, {0x0000,0x0000,0x0000}}};
2698 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2700 int cCount = cChars;
2701 WCHAR *input;
2702 IndicSyllable *syllables = NULL;
2703 int syllable_count = 0;
2704 BOOL modern = get_GSUB_Indic2(psa, psc);
2706 if (*pcGlyphs != cChars)
2708 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2709 return;
2712 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2713 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2715 /* Step 1: Decompose Vowels */
2716 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2717 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2719 /* Step 2: Reorder within Syllables */
2720 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2721 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2722 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2723 *pcGlyphs = cCount;
2725 /* Step 3: Base Form application to syllables */
2726 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2728 HeapFree(GetProcessHeap(),0,input);
2729 HeapFree(GetProcessHeap(),0,syllables);
2732 static int malayalam_lex(WCHAR c)
2734 return unicode_lex(c);
2737 static const VowelComponents Malayalam_vowels[] = {
2738 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2739 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2740 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2741 {0x0000, {0x0000,0x0000,0x0000}}};
2743 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2745 int cCount = cChars;
2746 WCHAR *input;
2747 IndicSyllable *syllables = NULL;
2748 int syllable_count = 0;
2749 BOOL modern = get_GSUB_Indic2(psa, psc);
2751 if (*pcGlyphs != cChars)
2753 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2754 return;
2757 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2758 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2760 /* Step 1: Decompose Vowels */
2761 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2762 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2764 /* Step 2: Reorder within Syllables */
2765 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2766 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2767 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2768 *pcGlyphs = cCount;
2770 /* Step 3: Base Form application to syllables */
2771 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2773 HeapFree(GetProcessHeap(),0,input);
2774 HeapFree(GetProcessHeap(),0,syllables);
2777 static int khmer_lex(WCHAR c)
2779 return unicode_lex(c);
2782 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2784 int cCount = cChars;
2785 WCHAR *input;
2786 IndicSyllable *syllables = NULL;
2787 int syllable_count = 0;
2789 if (*pcGlyphs != cChars)
2791 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2792 return;
2795 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2796 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2798 /* Step 1: Reorder within Syllables */
2799 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2800 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2801 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2802 *pcGlyphs = cCount;
2804 /* Step 2: Base Form application to syllables */
2805 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2807 HeapFree(GetProcessHeap(),0,input);
2808 HeapFree(GetProcessHeap(),0,syllables);
2811 static inline BOOL mongolian_wordbreak(WCHAR chr)
2813 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2816 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2818 INT *context_shape;
2819 INT dirL;
2820 int i;
2821 int char_index;
2822 int glyph_index;
2824 if (*pcGlyphs != cChars)
2826 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2827 return;
2830 if (!psa->fLogicalOrder && psa->fRTL)
2831 dirL = -1;
2832 else
2833 dirL = 1;
2835 if (!psc->GSUB_Table)
2836 return;
2838 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2840 for (i = 0; i < cChars; i++)
2842 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2844 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2845 context_shape[i] = Xn;
2846 else
2847 context_shape[i] = Xl;
2849 else
2851 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2852 context_shape[i] = Xr;
2853 else
2854 context_shape[i] = Xm;
2858 /* Contextual Shaping */
2859 if (dirL > 0)
2860 char_index = glyph_index = 0;
2861 else
2862 char_index = glyph_index = cChars-1;
2864 while(char_index < cChars && char_index >= 0)
2866 INT nextIndex;
2867 INT prevCount = *pcGlyphs;
2868 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2870 if (nextIndex > GSUB_E_NOGLYPH)
2872 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2873 glyph_index = nextIndex;
2874 char_index += dirL;
2876 else
2878 char_index += dirL;
2879 glyph_index += dirL;
2883 HeapFree(GetProcessHeap(),0,context_shape);
2886 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)
2888 int i,k;
2890 for (i = 0; i < cGlyphs; i++)
2892 int char_index[20];
2893 int char_count = 0;
2895 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2896 if (k>=0)
2898 for (; k < cChars && pwLogClust[k] == i; k++)
2899 char_index[char_count++] = k;
2902 if (char_count == 0)
2903 continue;
2905 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2907 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2908 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2910 else
2911 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2914 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2915 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2918 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 )
2920 int i;
2922 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2924 for (i = 0; i < cGlyphs; i++)
2925 if (pGlyphProp[i].sva.fZeroWidth)
2926 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2929 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 )
2931 int i;
2932 for (i = 0; i < cGlyphs; i++)
2934 pGlyphProp[i].sva.fClusterStart = 1;
2935 pGlyphProp[i].sva.fDiacritic = 0;
2936 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2938 if (pwGlyphs[i] == psc->sfp.wgDefault)
2939 pGlyphProp[i].sva.fZeroWidth = 0;
2940 else
2941 pGlyphProp[i].sva.fZeroWidth = 1;
2945 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 )
2947 int i,k;
2948 int initGlyph, finaGlyph;
2949 INT dirR, dirL;
2950 BYTE *spaces;
2952 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2953 memset(spaces,0,cGlyphs);
2955 if (psa->fLogicalOrder && psa->fRTL)
2957 initGlyph = 0;
2958 finaGlyph = cGlyphs-1;
2959 dirR = -1;
2960 dirL = 1;
2962 else
2964 initGlyph = cGlyphs-1;
2965 finaGlyph = 0;
2966 dirR = 1;
2967 dirL = -1;
2970 for (i = 0; i < cGlyphs; i++)
2972 for (k = 0; k < cChars; k++)
2973 if (pwLogClust[k] == i)
2975 if (pwcChars[k] == 0x0020)
2976 spaces[i] = 1;
2980 for (i = 0; i < cGlyphs; i++)
2982 int char_index[20];
2983 int char_count = 0;
2984 BOOL isInit, isFinal;
2986 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2987 if (k>=0)
2989 for (; k < cChars && pwLogClust[k] == i; k++)
2990 char_index[char_count++] = k;
2993 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2994 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2996 if (char_count == 0)
2997 continue;
2999 if (char_count == 1)
3001 if (pwcChars[char_index[0]] == 0x0020) /* space */
3003 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3004 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3006 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3007 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3008 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3010 if (!isInit && !isFinal)
3011 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3012 else if (isInit)
3013 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3014 else
3015 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3017 else if (!isInit)
3019 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3020 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3021 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3022 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3023 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3024 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3025 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3026 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3027 else
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3030 else if (!isInit && !isFinal)
3031 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3032 else
3033 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3035 else if (char_count == 2)
3037 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3038 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3039 else if (!isInit)
3040 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3041 else
3042 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3044 else if (!isInit && !isFinal)
3045 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3046 else
3047 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3050 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3051 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3052 HeapFree(GetProcessHeap(),0,spaces);
3055 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 )
3057 int i,k;
3059 for (i = 0; i < cGlyphs; i++)
3061 int char_index[20];
3062 int char_count = 0;
3064 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3065 if (k>=0)
3067 for (; k < cChars && pwLogClust[k] == i; k++)
3068 char_index[char_count++] = k;
3071 if (char_count == 0)
3072 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3073 else
3075 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3076 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3077 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3081 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3082 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3085 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 )
3087 int i;
3088 int finaGlyph;
3089 INT dirL;
3091 if (!psa->fLogicalOrder && psa->fRTL)
3093 finaGlyph = 0;
3094 dirL = -1;
3096 else
3098 finaGlyph = cGlyphs-1;
3099 dirL = 1;
3102 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3104 for (i = 0; i < cGlyphs; i++)
3106 int k;
3107 int char_index[20];
3108 int char_count = 0;
3110 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3111 if (k>=0)
3113 for (; k < cChars && pwLogClust[k] == i; k++)
3114 char_index[char_count++] = k;
3117 if (i == finaGlyph)
3118 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3119 else
3120 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3122 if (char_count == 0)
3123 continue;
3125 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3126 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3128 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3129 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3130 pGlyphProp[i].sva.fClusterStart = 0;
3133 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3135 /* Do not allow justification between marks and their base */
3136 for (i = 0; i < cGlyphs; i++)
3138 if (!pGlyphProp[i].sva.fClusterStart)
3139 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3143 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)
3145 int i,k;
3147 for (i = 0; i < cGlyphs; i++)
3149 int char_index[20];
3150 int char_count = 0;
3152 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3153 if (k>=0)
3155 for (; k < cChars && pwLogClust[k] == i; k++)
3156 char_index[char_count++] = k;
3159 if (char_count == 0)
3160 continue;
3162 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3164 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3165 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3167 else
3168 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3170 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3171 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3174 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)
3176 int i,k;
3178 for (i = 0; i < cGlyphs; i++)
3180 int char_index[20];
3181 int char_count = 0;
3183 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3184 if (k>=0)
3186 for (; k < cChars && pwLogClust[k] == i; k++)
3187 char_index[char_count++] = k;
3190 if (char_count == 0)
3191 continue;
3193 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3195 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3196 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3198 else
3199 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3201 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3202 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3204 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3205 for (i = 0; i < cGlyphs; i++)
3207 if (!pGlyphProp[i].sva.fClusterStart)
3209 pGlyphProp[i].sva.fDiacritic = 0;
3210 pGlyphProp[i].sva.fZeroWidth = 0;
3215 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)
3217 int i,k;
3219 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3220 for (i = 0; i < cGlyphs; i++)
3222 int char_index[20];
3223 int char_count = 0;
3225 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3226 if (k>=0)
3228 for (; k < cChars && pwLogClust[k] == i; k++)
3229 char_index[char_count++] = k;
3232 if (override_gsub)
3234 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3235 pGlyphProp[i].sva.fDiacritic = FALSE;
3236 pGlyphProp[i].sva.fZeroWidth = FALSE;
3239 if (char_count == 0)
3241 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3242 continue;
3245 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3247 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3248 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3250 else
3251 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3253 pGlyphProp[i].sva.fClusterStart = 0;
3254 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3255 switch (lexical(pwcChars[char_index[k]]))
3257 case lex_Matra_pre:
3258 case lex_Matra_post:
3259 case lex_Matra_above:
3260 case lex_Matra_below:
3261 case lex_Modifier:
3262 case lex_Halant:
3263 break;
3264 case lex_ZWJ:
3265 case lex_ZWNJ:
3266 /* check for dangling joiners */
3267 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3268 pGlyphProp[i].sva.fClusterStart = 1;
3269 else
3270 k = char_count;
3271 break;
3272 default:
3273 pGlyphProp[i].sva.fClusterStart = 1;
3274 break;
3278 if (use_syllables)
3280 IndicSyllable *syllables = NULL;
3281 int syllable_count = 0;
3282 BOOL modern = get_GSUB_Indic2(psa, psc);
3284 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3286 for (i = 0; i < syllable_count; i++)
3288 int j;
3289 WORD g = pwLogClust[syllables[i].start];
3290 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3292 if (pwLogClust[j] != g)
3294 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3295 pwLogClust[j] = g;
3300 HeapFree(GetProcessHeap(), 0, syllables);
3303 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3306 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 )
3308 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3311 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 )
3313 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3316 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 )
3318 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3321 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 )
3323 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3326 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 )
3328 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3331 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 )
3333 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3336 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 )
3338 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3341 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 )
3343 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3346 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 )
3348 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3351 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 )
3353 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3356 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 )
3358 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3361 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)
3363 load_ot_tables(hdc, psc);
3365 if (ShapingData[psa->eScript].charGlyphPropProc)
3366 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3367 else
3368 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3371 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3373 load_ot_tables(hdc, psc);
3375 if (ShapingData[psa->eScript].contextProc)
3376 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3379 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)
3381 int i;
3382 INT dirL;
3384 if (!rpRangeProperties)
3385 return;
3387 load_ot_tables(hdc, psc);
3389 if (!psc->GSUB_Table)
3390 return;
3392 if (scriptInformation[psa->eScript].a.fRTL && (!psa->fLogicalOrder || !psa->fRTL))
3393 dirL = -1;
3394 else
3395 dirL = 1;
3397 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3399 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3400 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3404 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3406 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3407 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3409 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3412 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3414 const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3415 int i;
3417 load_ot_tables(hdc, psc);
3419 if (!psc->GPOS_Table || !psc->otm)
3420 return;
3422 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3424 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3426 LoadedFeature *feature;
3428 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3429 if (!feature)
3430 continue;
3432 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3437 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3439 LoadedFeature *feature;
3440 int i;
3442 if (!ShapingData[psa->eScript].requiredFeatures)
3443 return S_OK;
3445 load_ot_tables(hdc, psc);
3447 /* we need to have at least one of the required features */
3448 i = 0;
3449 while (ShapingData[psa->eScript].requiredFeatures[i])
3451 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3452 if (feature)
3453 return S_OK;
3454 i++;
3457 return USP_E_SCRIPT_NOT_IN_FONT;
3460 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3461 SCRIPT_ANALYSIS *psa, int cMaxTags,
3462 OPENTYPE_TAG *pScriptTags, int *pcTags)
3464 HRESULT hr;
3465 OPENTYPE_TAG searching = 0x00000000;
3467 load_ot_tables(hdc, psc);
3469 if (psa && scriptInformation[psa->eScript].scriptTag)
3470 searching = scriptInformation[psa->eScript].scriptTag;
3472 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3473 if (FAILED(hr))
3474 *pcTags = 0;
3475 return hr;
3478 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3479 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3480 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3481 int *pcTags)
3483 HRESULT hr;
3484 OPENTYPE_TAG searching = 0x00000000;
3485 BOOL fellback = FALSE;
3487 load_ot_tables(hdc, psc);
3489 if (psa && psc->userLang != 0)
3490 searching = psc->userLang;
3492 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3493 if (FAILED(hr))
3495 fellback = TRUE;
3496 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3499 if (FAILED(hr) || fellback)
3500 *pcTags = 0;
3501 if (SUCCEEDED(hr) && fellback && psa)
3502 hr = E_INVALIDARG;
3503 return hr;
3506 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3507 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3508 OPENTYPE_TAG tagLangSys, int cMaxTags,
3509 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3511 HRESULT hr;
3512 BOOL filter = FALSE;
3514 load_ot_tables(hdc, psc);
3516 if (psa && scriptInformation[psa->eScript].scriptTag)
3518 FIXME("Filtering not implemented\n");
3519 filter = TRUE;
3522 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3524 if (FAILED(hr))
3525 *pcTags = 0;
3526 return hr;