comdlg32: Detach file dialog data after child windows were destroyed.
[wine.git] / dlls / usp10 / shape.c
blob40313863002fffd5932c302bf59983bf9584206d
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"
35 #include "wine/heap.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
39 #define FIRST_ARABIC_CHAR 0x0600
40 #define LAST_ARABIC_CHAR 0x06ff
42 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
43 WCHAR*, INT, WORD*, INT*, INT, WORD*);
45 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
63 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
64 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
66 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
68 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);
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
78 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 );
79 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 );
80 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 );
81 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 );
82 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 );
83 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 );
84 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 );
85 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 );
86 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 );
88 extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
89 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
90 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
92 enum joining_types {
93 jtU,
94 jtT,
95 jtR,
96 jtL,
97 jtD,
98 jtC
101 enum joined_forms {
102 Xn=0,
106 /* Syriac Alaph */
107 Afj,
108 Afn,
112 typedef struct tagVowelComponents
114 WCHAR base;
115 WCHAR parts[3];
116 } VowelComponents;
118 typedef struct tagConsonantComponents
120 WCHAR parts[3];
121 WCHAR output;
122 } ConsonantComponents;
124 typedef void (*second_reorder_function)(const WCHAR *chars, const IndicSyllable *syllable,
125 WORD *glyphs, const IndicSyllable *glyph_index, lexical_function lex);
127 typedef int (*combining_lexical_function)(WCHAR c);
129 /* the orders of joined_forms and contextual_features need to line up */
130 static const char *const contextual_features[] =
132 "isol",
133 "fina",
134 "init",
135 "medi",
136 /* Syriac Alaph */
137 "med2",
138 "fin2",
139 "fin3"
142 static OPENTYPE_FEATURE_RECORD standard_features[] =
144 { MS_MAKE_TAG('c','c','m','p'), 1},
145 { MS_MAKE_TAG('l','o','c','l'), 1},
148 static OPENTYPE_FEATURE_RECORD latin_features[] =
150 { MS_MAKE_TAG('l','o','c','l'), 1},
151 { MS_MAKE_TAG('c','c','m','p'), 1},
152 { MS_MAKE_TAG('l','i','g','a'), 1},
153 { MS_MAKE_TAG('c','l','i','g'), 1},
156 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
158 { MS_MAKE_TAG('k','e','r','n'), 1},
159 { MS_MAKE_TAG('m','a','r','k'), 1},
160 { MS_MAKE_TAG('m','k','m','k'), 1},
163 static OPENTYPE_FEATURE_RECORD arabic_features[] =
165 { MS_MAKE_TAG('r','l','i','g'), 1},
166 { MS_MAKE_TAG('c','a','l','t'), 1},
167 { MS_MAKE_TAG('l','i','g','a'), 1},
168 { MS_MAKE_TAG('d','l','i','g'), 1},
169 { MS_MAKE_TAG('c','s','w','h'), 1},
170 { MS_MAKE_TAG('m','s','e','t'), 1},
173 static const char *const required_arabic_features[] =
175 "fina",
176 "init",
177 "medi",
178 "rlig",
179 NULL
182 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
184 { MS_MAKE_TAG('c','u','r','s'), 1},
185 { MS_MAKE_TAG('k','e','r','n'), 1},
186 { MS_MAKE_TAG('m','a','r','k'), 1},
187 { MS_MAKE_TAG('m','k','m','k'), 1},
190 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
192 { MS_MAKE_TAG('c','c','m','p'), 1},
193 { MS_MAKE_TAG('d','l','i','g'), 0},
196 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
198 { MS_MAKE_TAG('k','e','r','n'), 1},
199 { MS_MAKE_TAG('m','a','r','k'), 1},
202 static OPENTYPE_FEATURE_RECORD syriac_features[] =
204 { MS_MAKE_TAG('r','l','i','g'), 1},
205 { MS_MAKE_TAG('c','a','l','t'), 1},
206 { MS_MAKE_TAG('l','i','g','a'), 1},
207 { MS_MAKE_TAG('d','l','i','g'), 1},
210 static const char *const required_syriac_features[] =
212 "fina",
213 "fin2",
214 "fin3",
215 "init",
216 "medi",
217 "med2",
218 "rlig",
219 NULL
222 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
224 { MS_MAKE_TAG('k','e','r','n'), 1},
225 { MS_MAKE_TAG('m','a','r','k'), 1},
226 { MS_MAKE_TAG('m','k','m','k'), 1},
229 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
231 /* Presentation forms */
232 { MS_MAKE_TAG('b','l','w','s'), 1},
233 { MS_MAKE_TAG('a','b','v','s'), 1},
234 { MS_MAKE_TAG('p','s','t','s'), 1},
237 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
239 { MS_MAKE_TAG('a','b','v','s'), 1},
240 { MS_MAKE_TAG('b','l','w','s'), 1},
243 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
245 { MS_MAKE_TAG('a','b','v','m'), 1},
246 { MS_MAKE_TAG('b','l','w','m'), 1},
249 static OPENTYPE_FEATURE_RECORD phags_features[] =
251 { MS_MAKE_TAG('a','b','v','s'), 1},
252 { MS_MAKE_TAG('b','l','w','s'), 1},
253 { MS_MAKE_TAG('c','a','l','t'), 1},
256 static OPENTYPE_FEATURE_RECORD thai_features[] =
258 { MS_MAKE_TAG('c','c','m','p'), 1},
261 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
263 { MS_MAKE_TAG('k','e','r','n'), 1},
264 { MS_MAKE_TAG('m','a','r','k'), 1},
265 { MS_MAKE_TAG('m','k','m','k'), 1},
268 static const char *const required_lao_features[] =
270 "ccmp",
271 NULL
274 static const char *const required_devanagari_features[] =
276 "nukt",
277 "akhn",
278 "rphf",
279 "blwf",
280 "half",
281 "vatu",
282 "pres",
283 "abvs",
284 "blws",
285 "psts",
286 "haln",
287 NULL
290 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
292 { MS_MAKE_TAG('p','r','e','s'), 1},
293 { MS_MAKE_TAG('a','b','v','s'), 1},
294 { MS_MAKE_TAG('b','l','w','s'), 1},
295 { MS_MAKE_TAG('p','s','t','s'), 1},
296 { MS_MAKE_TAG('h','a','l','n'), 1},
297 { MS_MAKE_TAG('c','a','l','t'), 1},
300 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
302 { MS_MAKE_TAG('k','e','r','n'), 1},
303 { MS_MAKE_TAG('d','i','s','t'), 1},
304 { MS_MAKE_TAG('a','b','v','m'), 1},
305 { MS_MAKE_TAG('b','l','w','m'), 1},
308 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
310 { MS_MAKE_TAG('l','i','g','a'), 1},
311 { MS_MAKE_TAG('c','l','i','g'), 1},
314 static const char *const required_bengali_features[] =
316 "nukt",
317 "akhn",
318 "rphf",
319 "blwf",
320 "half",
321 "vatu",
322 "pstf",
323 "init",
324 "abvs",
325 "blws",
326 "psts",
327 "haln",
328 NULL
331 static const char *const required_gurmukhi_features[] =
333 "nukt",
334 "akhn",
335 "rphf",
336 "blwf",
337 "half",
338 "pstf",
339 "vatu",
340 "cjct",
341 "pres",
342 "abvs",
343 "blws",
344 "psts",
345 "haln",
346 "calt",
347 NULL
350 static const char *const required_oriya_features[] =
352 "nukt",
353 "akhn",
354 "rphf",
355 "blwf",
356 "pstf",
357 "cjct",
358 "pres",
359 "abvs",
360 "blws",
361 "psts",
362 "haln",
363 "calt",
364 NULL
367 static const char *const required_tamil_features[] =
369 "nukt",
370 "akhn",
371 "rphf",
372 "pref",
373 "half",
374 "pres",
375 "abvs",
376 "blws",
377 "psts",
378 "haln",
379 "calt",
380 NULL
383 static const char *const required_telugu_features[] =
385 "nukt",
386 "akhn",
387 "rphf",
388 "pref",
389 "half",
390 "pstf",
391 "cjct",
392 "pres",
393 "abvs",
394 "blws",
395 "psts",
396 "haln",
397 "calt",
398 NULL
401 static OPENTYPE_FEATURE_RECORD khmer_features[] =
403 { MS_MAKE_TAG('p','r','e','s'), 1},
404 { MS_MAKE_TAG('b','l','w','s'), 1},
405 { MS_MAKE_TAG('a','b','v','s'), 1},
406 { MS_MAKE_TAG('p','s','t','s'), 1},
407 { MS_MAKE_TAG('c','l','i','g'), 1},
410 static const char *const required_khmer_features[] =
412 "pref",
413 "blwf",
414 "abvf",
415 "pstf",
416 "pres",
417 "blws",
418 "abvs",
419 "psts",
420 "clig",
421 NULL
424 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
426 { MS_MAKE_TAG('d','i','s','t'), 1},
427 { MS_MAKE_TAG('b','l','w','m'), 1},
428 { MS_MAKE_TAG('a','b','v','m'), 1},
429 { MS_MAKE_TAG('m','k','m','k'), 1},
432 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
434 { MS_MAKE_TAG('c','c','m','p'), 1},
435 { MS_MAKE_TAG('l','o','c','l'), 1},
436 { MS_MAKE_TAG('c','a','l','t'), 1},
437 { MS_MAKE_TAG('l','i','g','a'), 1},
440 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
442 { MS_MAKE_TAG('c','c','m','p'), 1},
443 { MS_MAKE_TAG('l','o','c','l'), 1},
444 { MS_MAKE_TAG('c','a','l','t'), 1},
445 { MS_MAKE_TAG('r','l','i','g'), 1},
448 typedef struct ScriptShapeDataTag {
449 TEXTRANGE_PROPERTIES defaultTextRange;
450 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
451 const char *const *requiredFeatures;
452 OPENTYPE_TAG newOtTag;
453 ContextualShapingProc contextProc;
454 ShapeCharGlyphPropProc charGlyphPropProc;
455 } ScriptShapeData;
457 /* in order of scripts */
458 static const ScriptShapeData ShapingData[] =
460 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
461 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
462 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
463 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
464 {{ standard_features, 2}, {NULL, 0}, NULL, 0, ContextualShape_Control, ShapeCharGlyphProp_Control},
465 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
466 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
467 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
468 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
469 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
470 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
471 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
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 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
475 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
476 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
477 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
478 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
479 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
480 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
481 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
482 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
483 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, 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_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, 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_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
497 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
498 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
499 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
500 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
501 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
502 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
503 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
504 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
505 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
506 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
511 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
512 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
513 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
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 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
522 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
523 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, 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 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
538 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
539 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
540 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
541 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
544 extern scriptData scriptInformation[];
546 static int GSUB_apply_feature_all_lookups(const void *header, LoadedFeature *feature,
547 WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count)
549 int i;
550 int out_index = GSUB_E_NOGLYPH;
552 TRACE("%i lookups\n", feature->lookup_count);
553 for (i = 0; i < feature->lookup_count; i++)
555 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
556 if (out_index != GSUB_E_NOGLYPH)
557 break;
559 if (out_index == GSUB_E_NOGLYPH)
560 TRACE("lookups found no glyphs\n");
561 else
563 int out2;
564 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
565 if (out2!=GSUB_E_NOGLYPH)
566 out_index = out2;
568 return out_index;
571 static OPENTYPE_TAG get_opentype_script(HDC hdc, const SCRIPT_ANALYSIS *psa,
572 const ScriptCache *script_cache, BOOL try_new)
574 UINT charset;
576 if (script_cache->userScript)
578 if (try_new && ShapingData[psa->eScript].newOtTag
579 && script_cache->userScript == scriptInformation[psa->eScript].scriptTag)
580 return ShapingData[psa->eScript].newOtTag;
582 return script_cache->userScript;
585 if (try_new && ShapingData[psa->eScript].newOtTag)
586 return ShapingData[psa->eScript].newOtTag;
588 if (scriptInformation[psa->eScript].scriptTag)
589 return scriptInformation[psa->eScript].scriptTag;
592 * fall back to the font charset
594 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
595 switch (charset)
597 case ANSI_CHARSET:
598 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
599 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
600 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
601 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
602 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
603 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
604 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
605 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
606 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
607 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
608 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
609 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
610 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
611 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
612 default: return MS_MAKE_TAG('l','a','t','n');
616 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
618 LoadedFeature *feature = NULL;
620 if (psc->GSUB_Table || psc->GPOS_Table)
622 int attempt = 2;
623 OPENTYPE_TAG tags;
624 OPENTYPE_TAG language;
625 OPENTYPE_TAG script = 0x00000000;
626 int cTags;
630 script = get_opentype_script(hdc,psa,psc,(attempt==2));
631 if (psc->userLang != 0)
632 language = psc->userLang;
633 else
634 language = MS_MAKE_TAG('d','f','l','t');
635 attempt--;
637 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
639 } while(attempt && !feature);
641 /* try in the default (latin) table */
642 if (!feature)
644 if (!script)
645 script = MS_MAKE_TAG('l','a','t','n');
646 OpenType_GetFontFeatureTags(psc, script, MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
650 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
651 return feature;
654 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)
656 LoadedFeature *feature;
658 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
659 if (!feature)
660 return GSUB_E_NOFEATURE;
662 TRACE("applying feature %s\n",feat);
663 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
666 static VOID *load_gsub_table(HDC hdc)
668 VOID* GSUB_Table = NULL;
669 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
670 if (length != GDI_ERROR)
672 GSUB_Table = heap_alloc(length);
673 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
674 TRACE("Loaded GSUB table of %i bytes\n",length);
676 return GSUB_Table;
679 static VOID *load_gpos_table(HDC hdc)
681 VOID* GPOS_Table = NULL;
682 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
683 if (length != GDI_ERROR)
685 GPOS_Table = heap_alloc(length);
686 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
687 TRACE("Loaded GPOS table of %i bytes\n",length);
689 return GPOS_Table;
692 static VOID *load_gdef_table(HDC hdc)
694 VOID* GDEF_Table = NULL;
695 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
696 if (length != GDI_ERROR)
698 GDEF_Table = heap_alloc(length);
699 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
700 TRACE("Loaded GDEF table of %i bytes\n",length);
702 return GDEF_Table;
705 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
707 if (!psc->GSUB_Table)
708 psc->GSUB_Table = load_gsub_table(hdc);
709 if (!psc->GPOS_Table)
710 psc->GPOS_Table = load_gpos_table(hdc);
711 if (!psc->GDEF_Table)
712 psc->GDEF_Table = load_gdef_table(hdc);
715 int SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc,
716 const WCHAR *chars, int write_dir, int count, const char *feature)
718 WORD *glyphs;
719 INT glyph_count = count;
720 INT rc;
722 glyphs = heap_calloc(count, 2 * sizeof(*glyphs));
723 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
724 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
725 if (rc > GSUB_E_NOGLYPH)
726 rc = count - glyph_count;
727 else
728 rc = 0;
730 heap_free(glyphs);
731 return rc;
734 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
736 int i;
738 for (i = 0; i < cGlyphs; i++)
740 if (!pGlyphProp[i].sva.fClusterStart)
742 int j;
743 for (j = 0; j < cChars; j++)
745 if (pwLogClust[j] == i)
747 int k = j;
748 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
749 k-=1;
750 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
751 pwLogClust[j] = pwLogClust[k];
758 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
760 if (changeCount == 0)
761 return;
762 else
764 int cluster_dir = pwLogClust[0] < pwLogClust[chars-1] ? 1 : -1;
765 int i;
766 int target_glyph = nextIndex - write_dir;
767 int target_index = -1;
768 int replacing_glyph = -1;
769 int changed = 0;
771 if (changeCount > 0)
773 if (write_dir > 0)
774 target_glyph = nextIndex - changeCount;
775 else
776 target_glyph = nextIndex + (changeCount + 1);
779 target_index = USP10_FindGlyphInLogClust(pwLogClust, chars, target_glyph);
780 if (target_index == -1)
782 ERR("Unable to find target glyph\n");
783 return;
786 if (changeCount < 0)
788 /* merge glyphs */
789 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
791 if (pwLogClust[i] == target_glyph)
792 continue;
793 if(pwLogClust[i] == replacing_glyph)
794 pwLogClust[i] = target_glyph;
795 else
797 changed--;
798 if (changed >= changeCount)
800 replacing_glyph = pwLogClust[i];
801 pwLogClust[i] = target_glyph;
803 else
804 break;
808 /* renumber trailing indexes */
809 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
811 if (pwLogClust[i] != target_glyph)
812 pwLogClust[i] += changeCount;
815 else
817 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
818 pwLogClust[i] += changeCount;
823 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 )
825 if (psc->GSUB_Table)
827 LoadedFeature *feature;
828 int lookup_index;
830 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
831 if (!feature)
832 return GSUB_E_NOFEATURE;
834 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
835 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
837 int i;
839 if (write_dir > 0)
840 i = 0;
841 else
842 i = *pcGlyphs-1;
843 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
844 while(i < *pcGlyphs && i >= 0)
846 INT nextIndex;
847 INT prevCount = *pcGlyphs;
849 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
850 if (*pcGlyphs != prevCount)
852 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
853 i = nextIndex;
855 else
856 i+=write_dir;
859 return *pcGlyphs;
861 return GSUB_E_NOFEATURE;
864 static void GPOS_apply_feature(const ScriptCache *psc, const OUTLINETEXTMETRICW *otm,
865 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance,
866 const LoadedFeature *feature, const WORD *glyphs, int glyph_count, GOFFSET *goffset)
868 int dir = analysis->fLogicalOrder && analysis->fRTL ? -1 : 1;
869 unsigned int start_idx, i, j;
871 TRACE("%i lookups\n", feature->lookup_count);
873 start_idx = dir < 0 ? glyph_count - 1 : 0;
874 for (i = 0; i < feature->lookup_count; i++)
876 for (j = 0; j < glyph_count; )
877 j += OpenType_apply_GPOS_lookup(psc, otm, logfont, analysis, advance,
878 feature->lookups[i], glyphs, start_idx + dir * j, glyph_count, goffset);
882 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
884 OPENTYPE_TAG tag;
885 HRESULT hr;
886 int count = 0;
888 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
890 return(SUCCEEDED(hr));
893 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
895 int i;
896 for (i = *pcGlyphs; i>=index; i--)
897 pwGlyphs[i+1] = pwGlyphs[i];
898 pwGlyphs[index] = glyph;
899 *pcGlyphs = *pcGlyphs+1;
900 if (write_dir < 0)
901 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
902 else
903 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
906 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)
908 CHAR *context_type;
909 int i,g;
910 WCHAR invalid = 0x25cc;
911 WORD invalid_glyph;
913 context_type = heap_alloc(cChars);
915 /* Mark invalid combinations */
916 for (i = 0; i < cChars; i++)
917 context_type[i] = lex(pwcChars[i]);
919 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
920 for (i = 1, g=1; i < cChars - 1; i++, g++)
922 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
924 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
925 g++;
929 heap_free(context_type);
932 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
934 int i;
935 for (i=0; i < cChars; i++)
937 switch (pwcChars[i])
939 case 0x000A:
940 case 0x000D:
941 pwOutGlyphs[i] = psc->sfp.wgBlank;
942 break;
943 default:
944 if (pwcChars[i] < 0x1C)
945 pwOutGlyphs[i] = psc->sfp.wgDefault;
946 else
947 pwOutGlyphs[i] = psc->sfp.wgBlank;
952 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
954 if (i + delta < 0)
955 return 0;
956 if ( i+ delta >= cchLen)
957 return 0;
959 i += delta;
961 return chars[i];
964 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
966 if (i + delta < 0)
968 if (psa->fLinkBefore)
969 return jtR;
970 else
971 return jtU;
973 if ( i+ delta >= cchLen)
975 if (psa->fLinkAfter)
976 return jtL;
977 else
978 return jtU;
981 i += delta;
983 if (context_type[i] == jtT)
984 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
985 else
986 return context_type[i];
989 static inline BOOL right_join_causing(CHAR joining_type)
991 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
994 static inline BOOL left_join_causing(CHAR joining_type)
996 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
999 static inline BOOL word_break_causing(WCHAR chr)
1001 /* we are working within a string of characters already guareented to
1002 be within one script, Syriac, so we do not worry about any character
1003 other than the space character outside of that range */
1004 return (chr == 0 || chr == 0x20 );
1007 static int combining_lexical_Arabic(WCHAR c)
1009 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1011 switch(c)
1013 case 0x064B:
1014 case 0x064C:
1015 case 0x064E:
1016 case 0x064F:
1017 case 0x0652:
1018 case 0x0657:
1019 case 0x0658:
1020 case 0x06E1: return Arab_DIAC1;
1021 case 0x064D:
1022 case 0x0650:
1023 case 0x0656: return Arab_DIAC2;
1024 case 0x0651: return Arab_DIAC3;
1025 case 0x0610:
1026 case 0x0611:
1027 case 0x0612:
1028 case 0x0613:
1029 case 0x0614:
1030 case 0x0659:
1031 case 0x06D6:
1032 case 0x06DC:
1033 case 0x06DF:
1034 case 0x06E0:
1035 case 0x06E2:
1036 case 0x06E4:
1037 case 0x06E7:
1038 case 0x06E8:
1039 case 0x06EB:
1040 case 0x06EC: return Arab_DIAC4;
1041 case 0x06E3:
1042 case 0x06EA:
1043 case 0x06ED: return Arab_DIAC5;
1044 case 0x0670: return Arab_DIAC6;
1045 case 0x0653: return Arab_DIAC7;
1046 case 0x0655:
1047 case 0x0654: return Arab_DIAC8;
1048 default: return Arab_Norm;
1053 * ContextualShape_Arabic
1055 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1057 CHAR *context_type;
1058 INT *context_shape;
1059 INT dirR, dirL;
1060 int i;
1061 int char_index;
1062 int glyph_index;
1064 if (*pcGlyphs != cChars)
1066 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1067 return;
1070 if (psa->fLogicalOrder && psa->fRTL)
1072 dirR = -1;
1073 dirL = 1;
1075 else
1077 dirR = 1;
1078 dirL = -1;
1081 load_ot_tables(hdc, psc);
1083 context_type = heap_alloc(cChars);
1084 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1086 for (i = 0; i < cChars; i++)
1087 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1089 for (i = 0; i < cChars; i++)
1091 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1092 context_shape[i] = Xr;
1093 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1094 context_shape[i] = Xl;
1095 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)))
1096 context_shape[i] = Xm;
1097 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1098 context_shape[i] = Xr;
1099 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1100 context_shape[i] = Xl;
1101 else
1102 context_shape[i] = Xn;
1105 /* Contextual Shaping */
1106 if (dirL > 0)
1107 char_index = glyph_index = 0;
1108 else
1109 char_index = glyph_index = cChars-1;
1111 while(char_index < cChars && char_index >= 0)
1113 BOOL shaped = FALSE;
1115 if (psc->GSUB_Table)
1117 INT nextIndex, offset = 0;
1118 INT prevCount = *pcGlyphs;
1120 /* Apply CCMP first */
1121 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1123 if (prevCount != *pcGlyphs)
1125 offset = *pcGlyphs - prevCount;
1126 if (dirL < 0)
1127 glyph_index -= offset * dirL;
1130 /* Apply the contextual feature */
1131 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1133 if (nextIndex > GSUB_E_NOGLYPH)
1135 UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1136 char_index += dirL;
1137 if (!offset)
1138 glyph_index = nextIndex;
1139 else
1141 offset = *pcGlyphs - prevCount;
1142 glyph_index += dirL * (offset + 1);
1144 shaped = TRUE;
1146 else if (nextIndex == GSUB_E_NOGLYPH)
1148 char_index += dirL;
1149 glyph_index += dirL;
1150 shaped = TRUE;
1154 if (!shaped)
1156 if (context_shape[char_index] == Xn)
1158 WORD newGlyph = pwOutGlyphs[glyph_index];
1159 if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
1161 /* fall back to presentation form B */
1162 WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
1163 if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1164 pwOutGlyphs[glyph_index] = newGlyph;
1167 char_index += dirL;
1168 glyph_index += dirL;
1172 heap_free(context_shape);
1173 heap_free(context_type);
1175 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1178 static int combining_lexical_Hebrew(WCHAR c)
1180 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};
1182 switch(c)
1184 case 0x05B0:
1185 case 0x05B1:
1186 case 0x05B2:
1187 case 0x05B3:
1188 case 0x05B4:
1189 case 0x05B5:
1190 case 0x05B6:
1191 case 0x05BB: return Hebr_DIAC;
1192 case 0x0599:
1193 case 0x05A1:
1194 case 0x05A9:
1195 case 0x05AE: return Hebr_CANT1;
1196 case 0x0597:
1197 case 0x05A8:
1198 case 0x05AC: return Hebr_CANT2;
1199 case 0x0592:
1200 case 0x0593:
1201 case 0x0594:
1202 case 0x0595:
1203 case 0x05A7:
1204 case 0x05AB: return Hebr_CANT3;
1205 case 0x0598:
1206 case 0x059C:
1207 case 0x059E:
1208 case 0x059F: return Hebr_CANT4;
1209 case 0x059D:
1210 case 0x05A0: return Hebr_CANT5;
1211 case 0x059B:
1212 case 0x05A5: return Hebr_CANT6;
1213 case 0x0591:
1214 case 0x05A3:
1215 case 0x05A6: return Hebr_CANT7;
1216 case 0x0596:
1217 case 0x05A4:
1218 case 0x05AA: return Hebr_CANT8;
1219 case 0x059A:
1220 case 0x05AD: return Hebr_CANT9;
1221 case 0x05AF: return Hebr_CANT10;
1222 case 0x05BC: return Hebr_DAGESH;
1223 case 0x05C4: return Hebr_DOTABV;
1224 case 0x05B9: return Hebr_HOLAM;
1225 case 0x05BD: return Hebr_METEG;
1226 case 0x05B7: return Hebr_PATAH;
1227 case 0x05B8: return Hebr_QAMATS;
1228 case 0x05BF: return Hebr_RAFE;
1229 case 0x05C1:
1230 case 0x05C2: return Hebr_SHINSIN;
1231 default: return Hebr_Norm;
1235 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1237 INT dirL;
1239 if (*pcGlyphs != cChars)
1241 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1242 return;
1245 if (!psa->fLogicalOrder && psa->fRTL)
1246 dirL = -1;
1247 else
1248 dirL = 1;
1250 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1254 * ContextualShape_Syriac
1257 static int combining_lexical_Syriac(WCHAR c)
1259 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};
1261 switch(c)
1263 case 0x730:
1264 case 0x733:
1265 case 0x736:
1266 case 0x73A:
1267 case 0x73D: return Syriac_DIAC1;
1268 case 0x731:
1269 case 0x734:
1270 case 0x737:
1271 case 0x73B:
1272 case 0x73E: return Syriac_DIAC2;
1273 case 0x740:
1274 case 0x749:
1275 case 0x74A: return Syriac_DIAC3;
1276 case 0x732:
1277 case 0x735:
1278 case 0x73F: return Syriac_DIAC4;
1279 case 0x738:
1280 case 0x739:
1281 case 0x73C: return Syriac_DIAC5;
1282 case 0x741:
1283 case 0x30A: return Syriac_DIAC6;
1284 case 0x742:
1285 case 0x325: return Syriac_DIAC7;
1286 case 0x747:
1287 case 0x303: return Syriac_DIAC8;
1288 case 0x748:
1289 case 0x32D:
1290 case 0x32E:
1291 case 0x330:
1292 case 0x331: return Syriac_DIAC9;
1293 case 0x308: return Syriac_DIAC10;
1294 case 0x304: return Syriac_DIAC11;
1295 case 0x307: return Syriac_DIAC12;
1296 case 0x323: return Syriac_DIAC13;
1297 case 0x743: return Syriac_DIAC14;
1298 case 0x744: return Syriac_DIAC15;
1299 case 0x745: return Syriac_DIAC16;
1300 case 0x746: return Syriac_DIAC17;
1301 default: return Syriac_Norm;
1305 #define ALAPH 0x710
1306 #define DALATH 0x715
1307 #define RISH 0x72A
1309 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1311 CHAR *context_type;
1312 INT *context_shape;
1313 INT dirR, dirL;
1314 int i;
1315 int char_index;
1316 int glyph_index;
1318 if (*pcGlyphs != cChars)
1320 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1321 return;
1324 if (!psa->fLogicalOrder && psa->fRTL)
1326 dirR = 1;
1327 dirL = -1;
1329 else
1331 dirR = -1;
1332 dirL = 1;
1335 load_ot_tables(hdc, psc);
1337 if (!psc->GSUB_Table)
1338 return;
1340 context_type = heap_alloc(cChars);
1341 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1343 for (i = 0; i < cChars; i++)
1344 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1346 for (i = 0; i < cChars; i++)
1348 if (pwcChars[i] == ALAPH)
1350 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1352 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1353 context_shape[i] = Afj;
1354 else if ( rchar != DALATH && rchar != RISH &&
1355 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1356 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1357 context_shape[i] = Afn;
1358 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1359 context_shape[i] = Afx;
1360 else
1361 context_shape[i] = Xn;
1363 else if (context_type[i] == jtR &&
1364 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1365 context_shape[i] = Xr;
1366 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1367 context_shape[i] = Xl;
1368 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)))
1369 context_shape[i] = Xm;
1370 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1371 context_shape[i] = Xr;
1372 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1373 context_shape[i] = Xl;
1374 else
1375 context_shape[i] = Xn;
1378 /* Contextual Shaping */
1379 if (dirL > 0)
1380 char_index = glyph_index = 0;
1381 else
1382 char_index = glyph_index = cChars-1;
1384 while(char_index < cChars && char_index >= 0)
1386 INT nextIndex, offset = 0;
1387 INT prevCount = *pcGlyphs;
1389 /* Apply CCMP first */
1390 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1392 if (prevCount != *pcGlyphs)
1394 offset = *pcGlyphs - prevCount;
1395 if (dirL < 0)
1396 glyph_index -= offset * dirL;
1399 /* Apply the contextual feature */
1400 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1401 if (nextIndex > GSUB_E_NOGLYPH)
1403 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1404 char_index += dirL;
1405 if (!offset)
1406 glyph_index = nextIndex;
1407 else
1409 offset = *pcGlyphs - prevCount;
1410 glyph_index += dirL * (offset + 1);
1413 else
1415 char_index += dirL;
1416 glyph_index += dirL;
1420 heap_free(context_shape);
1421 heap_free(context_type);
1423 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1426 static int combining_lexical_Thaana(WCHAR c)
1428 enum {Thaana_Norm=0, Thaana_FILI};
1430 switch(c)
1432 case 0x7A6:
1433 case 0x7A7:
1434 case 0x7A8:
1435 case 0x7A9:
1436 case 0x7AA:
1437 case 0x7AB:
1438 case 0x7AC:
1439 case 0x7AD:
1440 case 0x7AE:
1441 case 0x7AF: return Thaana_FILI;
1442 default: return Thaana_Norm;
1446 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1448 INT dirL;
1450 if (*pcGlyphs != cChars)
1452 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1453 return;
1456 if (!psa->fLogicalOrder && psa->fRTL)
1457 dirL = -1;
1458 else
1459 dirL = 1;
1461 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1465 * ContextualShape_Phags_pa
1468 #define phags_pa_CANDRABINDU 0xA873
1469 #define phags_pa_START 0xA840
1470 #define phags_pa_END 0xA87F
1472 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1474 INT *context_shape;
1475 INT dirR, dirL;
1476 int i;
1477 int char_index;
1478 int glyph_index;
1480 if (*pcGlyphs != cChars)
1482 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1483 return;
1486 if (!psa->fLogicalOrder && psa->fRTL)
1488 dirR = 1;
1489 dirL = -1;
1491 else
1493 dirR = -1;
1494 dirL = 1;
1497 load_ot_tables(hdc, psc);
1499 if (!psc->GSUB_Table)
1500 return;
1502 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1504 for (i = 0; i < cChars; i++)
1506 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1508 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1509 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1510 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1511 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1513 if (jrchar && jlchar)
1514 context_shape[i] = Xm;
1515 else if (jrchar)
1516 context_shape[i] = Xr;
1517 else if (jlchar)
1518 context_shape[i] = Xl;
1519 else
1520 context_shape[i] = Xn;
1522 else
1523 context_shape[i] = -1;
1526 /* Contextual Shaping */
1527 if (dirL > 0)
1528 char_index = glyph_index = 0;
1529 else
1530 char_index = glyph_index = cChars-1;
1532 while(char_index < cChars && char_index >= 0)
1534 if (context_shape[char_index] >= 0)
1536 INT nextIndex;
1537 INT prevCount = *pcGlyphs;
1538 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1540 if (nextIndex > GSUB_E_NOGLYPH)
1542 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1543 glyph_index = nextIndex;
1544 char_index += dirL;
1546 else
1548 char_index += dirL;
1549 glyph_index += dirL;
1552 else
1554 char_index += dirL;
1555 glyph_index += dirL;
1559 heap_free(context_shape);
1562 static int combining_lexical_Thai(WCHAR c)
1564 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1566 switch(c)
1568 case 0xE31:
1569 case 0xE34:
1570 case 0xE35:
1571 case 0xE36:
1572 case 0xE37: return Thai_ABOVE1;
1573 case 0xE47:
1574 case 0xE4D: return Thai_ABOVE2;
1575 case 0xE48:
1576 case 0xE49:
1577 case 0xE4A:
1578 case 0xE4B: return Thai_ABOVE3;
1579 case 0xE4C:
1580 case 0xE4E: return Thai_ABOVE4;
1581 case 0xE38:
1582 case 0xE39: return Thai_BELOW1;
1583 case 0xE3A: return Thai_BELOW2;
1584 case 0xE33: return Thai_AM;
1585 default: return Thai_Norm;
1589 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1591 INT dirL;
1593 if (*pcGlyphs != cChars)
1595 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1596 return;
1599 if (!psa->fLogicalOrder && psa->fRTL)
1600 dirL = -1;
1601 else
1602 dirL = 1;
1604 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1607 static int combining_lexical_Lao(WCHAR c)
1609 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1611 switch(c)
1613 case 0xEB1:
1614 case 0xEB4:
1615 case 0xEB5:
1616 case 0xEB6:
1617 case 0xEB7:
1618 case 0xEBB:
1619 case 0xECD: return Lao_ABOVE1;
1620 case 0xEC8:
1621 case 0xEC9:
1622 case 0xECA:
1623 case 0xECB:
1624 case 0xECC: return Lao_ABOVE2;
1625 case 0xEBC: return Lao_BELOW1;
1626 case 0xEB8:
1627 case 0xEB9: return Lao_BELOW2;
1628 case 0xEB3: return Lao_AM;
1629 default: return Lao_Norm;
1633 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1635 INT dirL;
1637 if (*pcGlyphs != cChars)
1639 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1640 return;
1643 if (!psa->fLogicalOrder && psa->fRTL)
1644 dirL = -1;
1645 else
1646 dirL = 1;
1648 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1651 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1653 int i;
1655 /* Replace */
1656 pwOutChars[cWalk] = replacements[0];
1657 cWalk=cWalk+1;
1659 /* Insert */
1660 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1662 int j;
1663 for (j = *pcChars; j > cWalk; j--)
1664 pwOutChars[j] = pwOutChars[j-1];
1665 *pcChars= *pcChars+1;
1666 pwOutChars[cWalk] = replacements[i];
1667 cWalk = cWalk+1;
1671 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1673 int i;
1674 int cWalk;
1676 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1678 for (i = 0; vowels[i].base != 0x0; i++)
1680 if (pwOutChars[cWalk] == vowels[i].base)
1682 int o = 0;
1683 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1684 if (vowels[i].parts[1]) { cWalk++; o++; }
1685 if (vowels[i].parts[2]) { cWalk++; o++; }
1686 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1687 break;
1693 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1695 int i;
1696 int offset = 0;
1697 int cWalk;
1699 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1701 for (i = 0; consonants[i].output!= 0x0; i++)
1703 int j;
1704 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1705 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1706 break;
1708 if (consonants[i].parts[j]==0x0) /* matched all */
1710 int k;
1711 j--;
1712 pwOutChars[cWalk] = consonants[i].output;
1713 for(k = cWalk+1; k < *pcChars - j; k++)
1714 pwOutChars[k] = pwOutChars[k+j];
1715 *pcChars = *pcChars - j;
1716 for (k = j ; k > 0; k--)
1717 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1718 offset += j;
1719 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1720 pwLogClust[k]--;
1721 break;
1724 cWalk++;
1728 static void Reorder_Ra_follows_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1730 if (s->ralf >= 0)
1732 int j;
1733 WORD Ra = pwChar[s->start];
1734 WORD H = pwChar[s->start+1];
1736 TRACE("Doing reorder of Ra to %i\n",s->base);
1737 for (j = s->start; j < s->base-1; j++)
1738 pwChar[j] = pwChar[j+2];
1739 pwChar[s->base-1] = Ra;
1740 pwChar[s->base] = H;
1742 s->ralf = s->base-1;
1743 s->base -= 2;
1747 static void Reorder_Ra_follows_matra(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1749 if (s->ralf >= 0)
1751 int j,loc;
1752 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1753 WORD Ra = pwChar[s->start];
1754 WORD H = pwChar[s->start+1];
1755 for (loc = s->end; loc > stop; loc--)
1756 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1757 break;
1759 TRACE("Doing reorder of Ra to %i\n",loc);
1760 for (j = s->start; j < loc-1; j++)
1761 pwChar[j] = pwChar[j+2];
1762 pwChar[loc-1] = Ra;
1763 pwChar[loc] = H;
1765 s->ralf = loc-1;
1766 s->base -= 2;
1767 if (s->blwf >= 0) s->blwf -= 2;
1768 if (s->pref >= 0) s->pref -= 2;
1772 static void Reorder_Ra_follows_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1774 if (s->ralf >= 0)
1776 int j;
1777 WORD Ra = pwChar[s->start];
1778 WORD H = pwChar[s->start+1];
1780 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1781 for (j = s->start; j < s->end-1; j++)
1782 pwChar[j] = pwChar[j+2];
1783 pwChar[s->end-1] = Ra;
1784 pwChar[s->end] = H;
1786 s->ralf = s->end-1;
1787 s->base -= 2;
1788 if (s->blwf >= 0) s->blwf -= 2;
1789 if (s->pref >= 0) s->pref -= 2;
1793 static void Reorder_Matra_precede_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1795 int i;
1797 /* reorder Matras */
1798 if (s->end > s->base)
1800 for (i = 1; i <= s->end-s->base; i++)
1802 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1804 int j;
1805 WCHAR c = pwChar[s->base+i];
1806 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1807 for (j = s->base+i; j > s->base; j--)
1808 pwChar[j] = pwChar[j-1];
1809 pwChar[s->base] = c;
1811 if (s->ralf >= s->base) s->ralf++;
1812 if (s->blwf >= s->base) s->blwf++;
1813 if (s->pref >= s->base) s->pref++;
1814 s->base ++;
1820 static void Reorder_Matra_precede_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1822 int i;
1824 /* reorder Matras */
1825 if (s->end > s->base)
1827 for (i = 1; i <= s->end-s->base; i++)
1829 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1831 int j;
1832 WCHAR c = pwChar[s->base+i];
1833 TRACE("Doing reorder of %x to %i\n",c,s->start);
1834 for (j = s->base+i; j > s->start; j--)
1835 pwChar[j] = pwChar[j-1];
1836 pwChar[s->start] = c;
1838 if (s->ralf >= 0) s->ralf++;
1839 if (s->blwf >= 0) s->blwf++;
1840 if (s->pref >= 0) s->pref++;
1841 s->base ++;
1847 static void SecondReorder_Blwf_follows_matra(const WCHAR *chars, const IndicSyllable *s,
1848 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1850 if (s->blwf >= 0 && g->blwf > g->base)
1852 int j,loc;
1853 int g_offset;
1854 for (loc = s->end; loc > s->blwf; loc--)
1855 if (lexical(chars[loc]) == lex_Matra_below || lexical(chars[loc]) == lex_Matra_above
1856 || lexical(chars[loc]) == lex_Matra_post)
1857 break;
1859 g_offset = (loc - s->blwf) - 1;
1861 if (loc != s->blwf)
1863 WORD blwf = glyphs[g->blwf];
1864 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1865 /* do not care about the pwChar array anymore, just the glyphs */
1866 for (j = 0; j < g_offset; j++)
1867 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1868 glyphs[g->blwf + g_offset] = blwf;
1873 static void SecondReorder_Matra_precede_base(const WCHAR *chars, const IndicSyllable *s,
1874 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1876 int i;
1878 /* reorder previously moved Matras to correct position*/
1879 for (i = s->start; i < s->base; i++)
1881 if (lexical(chars[i]) == lex_Matra_pre)
1883 int j;
1884 int g_start = g->start + i - s->start;
1885 if (g_start < g->base -1 )
1887 WCHAR og = glyphs[g_start];
1888 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1889 for (j = g_start; j < g->base-1; j++)
1890 glyphs[j] = glyphs[j+1];
1891 glyphs[g->base-1] = og;
1897 static void SecondReorder_Pref_precede_base(const IndicSyllable *s,
1898 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1900 if (s->pref >= 0 && g->pref > g->base)
1902 int j;
1903 WCHAR og = glyphs[g->pref];
1904 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1905 for (j = g->pref; j > g->base; j--)
1906 glyphs[j] = glyphs[j-1];
1907 glyphs[g->base] = og;
1911 static void Reorder_Like_Sinhala(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1913 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1914 if (s->start == s->base && s->base == s->end) return;
1915 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1917 Reorder_Ra_follows_base(pwChar, s, lexical);
1918 Reorder_Matra_precede_base(pwChar, s, lexical);
1921 static void Reorder_Like_Devanagari(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1923 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1924 if (s->start == s->base && s->base == s->end) return;
1925 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1927 Reorder_Ra_follows_matra(pwChar, s, lexical);
1928 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1931 static void Reorder_Like_Bengali(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1933 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1934 if (s->start == s->base && s->base == s->end) return;
1935 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1937 Reorder_Ra_follows_base(pwChar, s, lexical);
1938 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1941 static void Reorder_Like_Kannada(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1943 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1944 if (s->start == s->base && s->base == s->end) return;
1945 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1947 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1948 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1951 static void SecondReorder_Like_Telugu(const WCHAR *chars, const IndicSyllable *s,
1952 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1954 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1955 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1956 if (s->start == s->base && s->base == s->end) return;
1957 if (lexical(chars[s->base]) == lex_Vowel) return;
1959 SecondReorder_Blwf_follows_matra(chars, s, glyphs, g, lexical);
1962 static void SecondReorder_Like_Tamil(const WCHAR *chars, const IndicSyllable *s,
1963 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1965 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1966 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1967 if (s->start == s->base && s->base == s->end) return;
1968 if (lexical(chars[s->base]) == lex_Vowel) return;
1970 SecondReorder_Matra_precede_base(chars, s, glyphs, g, lexical);
1971 SecondReorder_Pref_precede_base(s, glyphs, g, lexical);
1975 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1977 if (shift == 0)
1978 return;
1980 if (glyph_index->start > index)
1981 glyph_index->start += shift;
1982 if (glyph_index->base > index)
1983 glyph_index->base+= shift;
1984 if (glyph_index->end > index)
1985 glyph_index->end+= shift;
1986 if (glyph_index->ralf > index)
1987 glyph_index->ralf+= shift;
1988 if (glyph_index->blwf > index)
1989 glyph_index->blwf+= shift;
1990 if (glyph_index->pref > index)
1991 glyph_index->pref+= shift;
1994 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 )
1996 int index = glyph_index->start;
1998 if (!feature)
1999 return;
2001 while(index <= glyph_index->end)
2003 INT nextIndex;
2004 INT prevCount = *pcGlyphs;
2005 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2006 if (nextIndex > GSUB_E_NOGLYPH)
2008 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2009 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2010 index = nextIndex;
2012 else
2013 index++;
2017 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2019 int i = 0;
2020 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)))))
2021 i++;
2022 if (index + i <= end-1)
2023 return index + i;
2024 else
2025 return -1;
2028 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)
2030 INT index, nextIndex;
2031 INT count,g_offset;
2033 count = syllable->base - syllable->start;
2035 g_offset = 0;
2036 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2037 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2039 INT prevCount = *pcGlyphs;
2040 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2041 if (nextIndex > GSUB_E_NOGLYPH)
2043 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2044 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2045 g_offset += (*pcGlyphs - prevCount);
2048 index+=2;
2049 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2053 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)
2055 INT nextIndex;
2056 INT prevCount = *pcGlyphs;
2058 if (syllable->ralf >= 0)
2060 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2061 if (nextIndex > GSUB_E_NOGLYPH)
2063 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2064 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2069 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2071 int i = 0;
2072 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2073 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2074 is_consonant(lexical(pwChars[index+i+1])))))
2075 i++;
2076 if (index + i <= end-1)
2077 return index+i;
2078 else
2079 return -1;
2082 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)
2084 INT index, nextIndex;
2085 INT count, g_offset=0;
2086 INT ralf = syllable->ralf;
2088 count = syllable->end - syllable->base;
2090 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2092 while (index >= 0)
2094 INT prevCount = *pcGlyphs;
2095 if (ralf >=0 && ralf < index)
2097 g_offset--;
2098 ralf = -1;
2101 if (!modern)
2103 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2104 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2105 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2108 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2109 if (nextIndex > GSUB_E_NOGLYPH)
2111 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2112 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2113 g_offset += (*pcGlyphs - prevCount);
2115 else if (!modern)
2117 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2118 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2119 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2122 index+=2;
2123 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2127 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)
2129 int c;
2130 int overall_shift = 0;
2131 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2132 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2133 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2134 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2135 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2136 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2137 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2138 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2139 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2140 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2141 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2142 IndicSyllable glyph_indexs;
2144 for (c = 0; c < syllable_count; c++)
2146 int old_end;
2147 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2148 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2149 old_end = glyph_indexs.end;
2151 if (locl)
2153 TRACE("applying feature locl\n");
2154 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2156 if (nukt)
2158 TRACE("applying feature nukt\n");
2159 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2161 if (akhn)
2163 TRACE("applying feature akhn\n");
2164 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2167 if (rphf)
2168 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2169 if (rkrf)
2171 TRACE("applying feature rkrf\n");
2172 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2174 if (pref)
2175 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2176 if (blwf)
2178 if (!modern)
2179 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2181 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2184 if (half)
2185 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2186 if (pstf)
2188 TRACE("applying feature pstf\n");
2189 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2191 if (vatu)
2193 TRACE("applying feature vatu\n");
2194 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2196 if (cjct)
2198 TRACE("applying feature cjct\n");
2199 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2202 if (second_reorder)
2203 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2205 overall_shift += glyph_indexs.end - old_end;
2209 static inline int unicode_lex(WCHAR c)
2211 int type;
2213 if (!c) return lex_Generic;
2214 if (c == 0x200D) return lex_ZWJ;
2215 if (c == 0x200C) return lex_ZWNJ;
2216 if (c == 0x00A0) return lex_NBSP;
2218 type = get_table_entry( indic_syllabic_table, c );
2220 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2222 switch( type )
2224 case 0x0d07: /* Unknown */
2225 case 0x0e07: /* Unknown */
2226 default: return lex_Generic;
2227 case 0x0001:
2228 case 0x0002:
2229 case 0x0011:
2230 case 0x0012:
2231 case 0x0013:
2232 case 0x0014: return lex_Modifier;
2233 case 0x0003:
2234 case 0x0009:
2235 case 0x000a:
2236 case 0x000b:
2237 case 0x000d:
2238 case 0x000e:
2239 case 0x000f:
2240 case 0x0010: return lex_Consonant;
2241 case 0x0004: return lex_Nukta;
2242 case 0x0005: return lex_Halant;
2243 case 0x0006:
2244 case 0x0008: return lex_Vowel;
2245 case 0x0007:
2246 case 0x0107: return lex_Matra_post;
2247 case 0x0207:
2248 case 0x0307: return lex_Matra_pre;
2249 case 0x0807:
2250 case 0x0907:
2251 case 0x0a07:
2252 case 0x0b07:
2253 case 0x0c07:
2254 case 0x0407: return lex_Composed_Vowel;
2255 case 0x0507: return lex_Matra_above;
2256 case 0x0607: return lex_Matra_below;
2257 case 0x000c:
2258 case 0x0015: return lex_Ra;
2262 static int sinhala_lex(WCHAR c)
2264 switch (c)
2266 case 0x0DDA:
2267 case 0x0DDD:
2268 case 0x0DDC:
2269 case 0x0DDE: return lex_Matra_post;
2270 default:
2271 return unicode_lex(c);
2275 static const VowelComponents Sinhala_vowels[] = {
2276 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2277 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2278 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2279 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2280 {0x0000, {0x0000,0x0000,0x0}}};
2282 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2284 int cCount = cChars;
2285 int i;
2286 WCHAR *input;
2287 IndicSyllable *syllables = NULL;
2288 int syllable_count = 0;
2290 if (*pcGlyphs != cChars)
2292 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2293 return;
2296 input = heap_alloc(3 * cChars * sizeof(*input));
2298 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2300 /* Step 1: Decompose multi part vowels */
2301 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2303 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2305 /* Step 2: Reorder within Syllables */
2306 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2307 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2309 /* Step 3: Strip dangling joiners */
2310 for (i = 0; i < cCount; i++)
2312 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2313 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2314 input[i] = 0x0020;
2317 /* Step 4: Base Form application to syllables */
2318 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2319 *pcGlyphs = cCount;
2320 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2322 heap_free(input);
2323 heap_free(syllables);
2326 static int devanagari_lex(WCHAR c)
2328 switch (c)
2330 case 0x0930: return lex_Ra;
2331 default:
2332 return unicode_lex(c);
2336 static const ConsonantComponents Devanagari_consonants[] ={
2337 {{0x0928, 0x093C, 0x00000}, 0x0929},
2338 {{0x0930, 0x093C, 0x00000}, 0x0931},
2339 {{0x0933, 0x093C, 0x00000}, 0x0934},
2340 {{0x0915, 0x093C, 0x00000}, 0x0958},
2341 {{0x0916, 0x093C, 0x00000}, 0x0959},
2342 {{0x0917, 0x093C, 0x00000}, 0x095A},
2343 {{0x091C, 0x093C, 0x00000}, 0x095B},
2344 {{0x0921, 0x093C, 0x00000}, 0x095C},
2345 {{0x0922, 0x093C, 0x00000}, 0x095D},
2346 {{0x092B, 0x093C, 0x00000}, 0x095E},
2347 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2349 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2351 int cCount = cChars;
2352 WCHAR *input;
2353 IndicSyllable *syllables = NULL;
2354 int syllable_count = 0;
2355 BOOL modern = get_GSUB_Indic2(psa, psc);
2357 if (*pcGlyphs != cChars)
2359 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2360 return;
2363 input = heap_alloc(cChars * sizeof(*input));
2364 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2366 /* Step 1: Compose Consonant and Nukta */
2367 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2368 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2370 /* Step 2: Reorder within Syllables */
2371 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2372 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2373 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2374 *pcGlyphs = cCount;
2376 /* Step 3: Base Form application to syllables */
2377 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2379 heap_free(input);
2380 heap_free(syllables);
2383 static int bengali_lex(WCHAR c)
2385 switch (c)
2387 case 0x09B0: return lex_Ra;
2388 default:
2389 return unicode_lex(c);
2393 static const VowelComponents Bengali_vowels[] = {
2394 {0x09CB, {0x09C7,0x09BE,0x0000}},
2395 {0x09CC, {0x09C7,0x09D7,0x0000}},
2396 {0x0000, {0x0000,0x0000,0x0000}}};
2398 static const ConsonantComponents Bengali_consonants[] = {
2399 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2400 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2401 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2402 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2403 {{0x0000,0x0000,0x0000}, 0x0000}};
2405 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2407 int cCount = cChars;
2408 WCHAR *input;
2409 IndicSyllable *syllables = NULL;
2410 int syllable_count = 0;
2411 BOOL modern = get_GSUB_Indic2(psa, psc);
2413 if (*pcGlyphs != cChars)
2415 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2416 return;
2419 input = heap_alloc(2 * cChars * sizeof(*input));
2420 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2422 /* Step 1: Decompose Vowels and Compose Consonants */
2423 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2424 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2425 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2427 /* Step 2: Reorder within Syllables */
2428 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2429 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2430 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2431 *pcGlyphs = cCount;
2433 /* Step 3: Initial form is only applied to the beginning of words */
2434 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2436 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2438 int index = cCount;
2439 int gCount = 1;
2440 if (index > 0) index++;
2442 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2446 /* Step 4: Base Form application to syllables */
2447 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2449 heap_free(input);
2450 heap_free(syllables);
2453 static int gurmukhi_lex(WCHAR c)
2455 if (c == 0x0A71)
2456 return lex_Modifier;
2457 else
2458 return unicode_lex(c);
2461 static const ConsonantComponents Gurmukhi_consonants[] = {
2462 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2463 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2464 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2465 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2466 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2467 {{0x0000,0x0000,0x0000}, 0x0000}};
2469 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2471 int cCount = cChars;
2472 WCHAR *input;
2473 IndicSyllable *syllables = NULL;
2474 int syllable_count = 0;
2475 BOOL modern = get_GSUB_Indic2(psa, psc);
2477 if (*pcGlyphs != cChars)
2479 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2480 return;
2483 input = heap_alloc(cChars * sizeof(*input));
2484 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2486 /* Step 1: Compose Consonants */
2487 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2488 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2490 /* Step 2: Reorder within Syllables */
2491 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2492 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2493 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2494 *pcGlyphs = cCount;
2496 /* Step 3: Base Form application to syllables */
2497 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2499 heap_free(input);
2500 heap_free(syllables);
2503 static int gujarati_lex(WCHAR c)
2505 switch (c)
2507 case 0x0AB0: return lex_Ra;
2508 default:
2509 return unicode_lex(c);
2513 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2515 int cCount = cChars;
2516 WCHAR *input;
2517 IndicSyllable *syllables = NULL;
2518 int syllable_count = 0;
2519 BOOL modern = get_GSUB_Indic2(psa, psc);
2521 if (*pcGlyphs != cChars)
2523 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2524 return;
2527 input = heap_alloc(cChars * sizeof(*input));
2528 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2530 /* Step 1: Reorder within Syllables */
2531 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2532 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2533 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2534 *pcGlyphs = cCount;
2536 /* Step 2: Base Form application to syllables */
2537 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2539 heap_free(input);
2540 heap_free(syllables);
2543 static int oriya_lex(WCHAR c)
2545 switch (c)
2547 case 0x0B30: return lex_Ra;
2548 default:
2549 return unicode_lex(c);
2553 static const VowelComponents Oriya_vowels[] = {
2554 {0x0B48, {0x0B47,0x0B56,0x0000}},
2555 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2556 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2557 {0x0000, {0x0000,0x0000,0x0000}}};
2559 static const ConsonantComponents Oriya_consonants[] = {
2560 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2561 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2562 {{0x0000,0x0000,0x0000}, 0x0000}};
2564 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2566 int cCount = cChars;
2567 WCHAR *input;
2568 IndicSyllable *syllables = NULL;
2569 int syllable_count = 0;
2570 BOOL modern = get_GSUB_Indic2(psa, psc);
2572 if (*pcGlyphs != cChars)
2574 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2575 return;
2578 input = heap_alloc(2 * cChars * sizeof(*input));
2579 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2581 /* Step 1: Decompose Vowels and Compose Consonants */
2582 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2583 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2584 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2586 /* Step 2: Reorder within Syllables */
2587 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2588 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2589 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2590 *pcGlyphs = cCount;
2592 /* Step 3: Base Form application to syllables */
2593 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2595 heap_free(input);
2596 heap_free(syllables);
2599 static int tamil_lex(WCHAR c)
2601 return unicode_lex(c);
2604 static const VowelComponents Tamil_vowels[] = {
2605 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2606 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2607 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2608 {0x0000, {0x0000,0x0000,0x0000}}};
2610 static const ConsonantComponents Tamil_consonants[] = {
2611 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2612 {{0x0000,0x0000,0x0000}, 0x0000}};
2614 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2616 int cCount = cChars;
2617 WCHAR *input;
2618 IndicSyllable *syllables = NULL;
2619 int syllable_count = 0;
2620 BOOL modern = get_GSUB_Indic2(psa, psc);
2622 if (*pcGlyphs != cChars)
2624 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2625 return;
2628 input = heap_alloc(2 * cChars * sizeof(*input));
2629 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2631 /* Step 1: Decompose Vowels and Compose Consonants */
2632 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2633 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2634 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2636 /* Step 2: Reorder within Syllables */
2637 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2638 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2639 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2640 *pcGlyphs = cCount;
2642 /* Step 3: Base Form application to syllables */
2643 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2645 heap_free(input);
2646 heap_free(syllables);
2649 static int telugu_lex(WCHAR c)
2651 switch (c)
2653 case 0x0C43:
2654 case 0x0C44: return lex_Modifier;
2655 default:
2656 return unicode_lex(c);
2660 static const VowelComponents Telugu_vowels[] = {
2661 {0x0C48, {0x0C46,0x0C56,0x0000}},
2662 {0x0000, {0x0000,0x0000,0x0000}}};
2664 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2666 int cCount = cChars;
2667 WCHAR *input;
2668 IndicSyllable *syllables = NULL;
2669 int syllable_count = 0;
2670 BOOL modern = get_GSUB_Indic2(psa, psc);
2672 if (*pcGlyphs != cChars)
2674 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2675 return;
2678 input = heap_alloc(2 * cChars * sizeof(*input));
2679 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2681 /* Step 1: Decompose Vowels */
2682 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2683 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2685 /* Step 2: Reorder within Syllables */
2686 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2687 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2688 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2689 *pcGlyphs = cCount;
2691 /* Step 3: Base Form application to syllables */
2692 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2694 heap_free(input);
2695 heap_free(syllables);
2698 static int kannada_lex(WCHAR c)
2700 switch (c)
2702 case 0x0CB0: return lex_Ra;
2703 default:
2704 return unicode_lex(c);
2708 static const VowelComponents Kannada_vowels[] = {
2709 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2710 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2711 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2712 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2713 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2714 {0x0000, {0x0000,0x0000,0x0000}}};
2716 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2718 int cCount = cChars;
2719 WCHAR *input;
2720 IndicSyllable *syllables = NULL;
2721 int syllable_count = 0;
2722 BOOL modern = get_GSUB_Indic2(psa, psc);
2724 if (*pcGlyphs != cChars)
2726 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2727 return;
2730 input = heap_alloc(3 * cChars * sizeof(*input));
2731 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2733 /* Step 1: Decompose Vowels */
2734 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2735 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2737 /* Step 2: Reorder within Syllables */
2738 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2739 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2740 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2741 *pcGlyphs = cCount;
2743 /* Step 3: Base Form application to syllables */
2744 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2746 heap_free(input);
2747 heap_free(syllables);
2750 static int malayalam_lex(WCHAR c)
2752 return unicode_lex(c);
2755 static const VowelComponents Malayalam_vowels[] = {
2756 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2757 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2758 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2759 {0x0000, {0x0000,0x0000,0x0000}}};
2761 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2763 int cCount = cChars;
2764 WCHAR *input;
2765 IndicSyllable *syllables = NULL;
2766 int syllable_count = 0;
2767 BOOL modern = get_GSUB_Indic2(psa, psc);
2769 if (*pcGlyphs != cChars)
2771 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2772 return;
2775 input = heap_alloc(2 * cChars * sizeof(*input));
2776 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2778 /* Step 1: Decompose Vowels */
2779 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2780 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2782 /* Step 2: Reorder within Syllables */
2783 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2784 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2785 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2786 *pcGlyphs = cCount;
2788 /* Step 3: Base Form application to syllables */
2789 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2791 heap_free(input);
2792 heap_free(syllables);
2795 static int khmer_lex(WCHAR c)
2797 return unicode_lex(c);
2800 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2802 int cCount = cChars;
2803 WCHAR *input;
2804 IndicSyllable *syllables = NULL;
2805 int syllable_count = 0;
2807 if (*pcGlyphs != cChars)
2809 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2810 return;
2813 input = heap_alloc(cChars * sizeof(*input));
2814 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2816 /* Step 1: Reorder within Syllables */
2817 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2818 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2819 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2820 *pcGlyphs = cCount;
2822 /* Step 2: Base Form application to syllables */
2823 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2825 heap_free(input);
2826 heap_free(syllables);
2829 static inline BOOL mongolian_wordbreak(WCHAR chr)
2831 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2834 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2836 INT *context_shape;
2837 INT dirL;
2838 int i;
2839 int char_index;
2840 int glyph_index;
2842 if (*pcGlyphs != cChars)
2844 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2845 return;
2848 if (!psa->fLogicalOrder && psa->fRTL)
2849 dirL = -1;
2850 else
2851 dirL = 1;
2853 if (!psc->GSUB_Table)
2854 return;
2856 context_shape = heap_alloc(cChars * sizeof(*context_shape));
2858 for (i = 0; i < cChars; i++)
2860 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2862 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2863 context_shape[i] = Xn;
2864 else
2865 context_shape[i] = Xl;
2867 else
2869 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2870 context_shape[i] = Xr;
2871 else
2872 context_shape[i] = Xm;
2876 /* Contextual Shaping */
2877 if (dirL > 0)
2878 char_index = glyph_index = 0;
2879 else
2880 char_index = glyph_index = cChars-1;
2882 while(char_index < cChars && char_index >= 0)
2884 INT nextIndex;
2885 INT prevCount = *pcGlyphs;
2886 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2888 if (nextIndex > GSUB_E_NOGLYPH)
2890 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2891 glyph_index = nextIndex;
2892 char_index += dirL;
2894 else
2896 char_index += dirL;
2897 glyph_index += dirL;
2901 heap_free(context_shape);
2904 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)
2906 int i,k;
2908 for (i = 0; i < cGlyphs; i++)
2910 int char_index[20];
2911 int char_count = 0;
2913 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2914 if (k>=0)
2916 for (; k < cChars && pwLogClust[k] == i; k++)
2917 char_index[char_count++] = k;
2920 if (char_count == 0)
2921 continue;
2923 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2925 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2926 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2928 else
2929 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2932 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2933 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2936 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 )
2938 int i;
2940 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2942 for (i = 0; i < cGlyphs; i++)
2943 if (pGlyphProp[i].sva.fZeroWidth)
2944 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2947 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 )
2949 int i;
2950 for (i = 0; i < cGlyphs; i++)
2952 pGlyphProp[i].sva.fClusterStart = 1;
2953 pGlyphProp[i].sva.fDiacritic = 0;
2954 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2956 if (pwGlyphs[i] == psc->sfp.wgDefault)
2957 pGlyphProp[i].sva.fZeroWidth = 0;
2958 else
2959 pGlyphProp[i].sva.fZeroWidth = 1;
2963 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 )
2965 int i,k;
2966 int initGlyph, finaGlyph;
2967 INT dirR, dirL;
2968 BYTE *spaces;
2970 spaces = heap_alloc(cGlyphs);
2971 memset(spaces,0,cGlyphs);
2973 if (psa->fLogicalOrder && psa->fRTL)
2975 initGlyph = 0;
2976 finaGlyph = cGlyphs-1;
2977 dirR = -1;
2978 dirL = 1;
2980 else
2982 initGlyph = cGlyphs-1;
2983 finaGlyph = 0;
2984 dirR = 1;
2985 dirL = -1;
2988 for (i = 0; i < cGlyphs; i++)
2990 for (k = 0; k < cChars; k++)
2991 if (pwLogClust[k] == i)
2993 if (pwcChars[k] == 0x0020)
2994 spaces[i] = 1;
2998 for (i = 0; i < cGlyphs; i++)
3000 int char_index[20];
3001 int char_count = 0;
3002 BOOL isInit, isFinal;
3004 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3005 if (k>=0)
3007 for (; k < cChars && pwLogClust[k] == i; k++)
3008 char_index[char_count++] = k;
3011 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3012 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3014 if (char_count == 0)
3015 continue;
3017 if (char_count == 1)
3019 if (pwcChars[char_index[0]] == 0x0020) /* space */
3021 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3022 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3024 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3025 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3026 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3028 if (!isInit && !isFinal)
3029 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3030 else if (isInit)
3031 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3032 else
3033 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3035 else if (!isInit)
3037 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3038 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3039 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3040 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3041 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3042 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3043 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3044 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3045 else
3046 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3048 else if (!isInit && !isFinal)
3049 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3050 else
3051 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3053 else if (char_count == 2)
3055 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3056 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3057 else if (!isInit)
3058 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3059 else
3060 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3062 else if (!isInit && !isFinal)
3063 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3064 else
3065 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3068 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3069 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3070 heap_free(spaces);
3073 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 )
3075 int i,k;
3077 for (i = 0; i < cGlyphs; i++)
3079 int char_index[20];
3080 int char_count = 0;
3082 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3083 if (k>=0)
3085 for (; k < cChars && pwLogClust[k] == i; k++)
3086 char_index[char_count++] = k;
3089 if (char_count == 0)
3090 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3091 else
3093 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3094 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3095 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3099 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3100 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3103 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 )
3105 int i;
3106 int finaGlyph;
3107 INT dirL;
3109 if (!psa->fLogicalOrder && psa->fRTL)
3111 finaGlyph = 0;
3112 dirL = -1;
3114 else
3116 finaGlyph = cGlyphs-1;
3117 dirL = 1;
3120 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3122 for (i = 0; i < cGlyphs; i++)
3124 int k;
3125 int char_index[20];
3126 int char_count = 0;
3128 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3129 if (k>=0)
3131 for (; k < cChars && pwLogClust[k] == i; k++)
3132 char_index[char_count++] = k;
3135 if (i == finaGlyph)
3136 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3137 else
3138 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3140 if (char_count == 0)
3141 continue;
3143 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3144 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3146 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3147 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3148 pGlyphProp[i].sva.fClusterStart = 0;
3151 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3153 /* Do not allow justification between marks and their base */
3154 for (i = 0; i < cGlyphs; i++)
3156 if (!pGlyphProp[i].sva.fClusterStart)
3157 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3161 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)
3163 int i,k;
3165 for (i = 0; i < cGlyphs; i++)
3167 int char_index[20];
3168 int char_count = 0;
3170 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3171 if (k>=0)
3173 for (; k < cChars && pwLogClust[k] == i; k++)
3174 char_index[char_count++] = k;
3177 if (char_count == 0)
3178 continue;
3180 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3182 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3183 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3185 else
3186 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3188 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3189 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3192 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)
3194 int i,k;
3196 for (i = 0; i < cGlyphs; i++)
3198 int char_index[20];
3199 int char_count = 0;
3201 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3202 if (k>=0)
3204 for (; k < cChars && pwLogClust[k] == i; k++)
3205 char_index[char_count++] = k;
3208 if (char_count == 0)
3209 continue;
3211 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3213 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3214 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3216 else
3217 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3219 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3220 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3222 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3223 for (i = 0; i < cGlyphs; i++)
3225 if (!pGlyphProp[i].sva.fClusterStart)
3227 pGlyphProp[i].sva.fDiacritic = 0;
3228 pGlyphProp[i].sva.fZeroWidth = 0;
3233 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)
3235 int i,k;
3237 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3238 for (i = 0; i < cGlyphs; i++)
3240 int char_index[20];
3241 int char_count = 0;
3243 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3244 if (k>=0)
3246 for (; k < cChars && pwLogClust[k] == i; k++)
3247 char_index[char_count++] = k;
3250 if (override_gsub)
3252 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3253 pGlyphProp[i].sva.fDiacritic = FALSE;
3254 pGlyphProp[i].sva.fZeroWidth = FALSE;
3257 if (char_count == 0)
3259 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3260 continue;
3263 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3265 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3266 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3268 else
3269 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3271 pGlyphProp[i].sva.fClusterStart = 0;
3272 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3273 switch (lexical(pwcChars[char_index[k]]))
3275 case lex_Matra_pre:
3276 case lex_Matra_post:
3277 case lex_Matra_above:
3278 case lex_Matra_below:
3279 case lex_Modifier:
3280 case lex_Halant:
3281 break;
3282 case lex_ZWJ:
3283 case lex_ZWNJ:
3284 /* check for dangling joiners */
3285 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3286 pGlyphProp[i].sva.fClusterStart = 1;
3287 else
3288 k = char_count;
3289 break;
3290 default:
3291 pGlyphProp[i].sva.fClusterStart = 1;
3292 break;
3296 if (use_syllables)
3298 IndicSyllable *syllables = NULL;
3299 int syllable_count = 0;
3300 BOOL modern = get_GSUB_Indic2(psa, psc);
3302 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3304 for (i = 0; i < syllable_count; i++)
3306 int j;
3307 WORD g = pwLogClust[syllables[i].start];
3308 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3310 if (pwLogClust[j] != g)
3312 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3313 pwLogClust[j] = g;
3318 heap_free(syllables);
3321 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3324 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 )
3326 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3329 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 )
3331 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3334 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 )
3336 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3339 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 )
3341 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3344 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 )
3346 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3349 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 )
3351 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3354 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 )
3356 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3359 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 )
3361 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3364 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 )
3366 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3369 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 )
3371 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3374 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 )
3376 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3379 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)
3381 load_ot_tables(hdc, psc);
3383 if (ShapingData[psa->eScript].charGlyphPropProc)
3384 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3385 else
3386 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3389 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3391 load_ot_tables(hdc, psc);
3393 if (ShapingData[psa->eScript].contextProc)
3394 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3397 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)
3399 int i;
3400 INT dirL;
3402 if (!rpRangeProperties)
3403 return;
3405 load_ot_tables(hdc, psc);
3407 if (!psc->GSUB_Table)
3408 return;
3410 if (scriptInformation[psa->eScript].a.fRTL && (!psa->fLogicalOrder || !psa->fRTL))
3411 dirL = -1;
3412 else
3413 dirL = 1;
3415 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3417 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3418 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3422 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3424 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3425 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3427 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3430 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3432 const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3433 int i;
3435 load_ot_tables(hdc, psc);
3437 if (!psc->GPOS_Table || !psc->otm)
3438 return;
3440 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3442 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3444 LoadedFeature *feature;
3446 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3447 if (!feature)
3448 continue;
3450 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3455 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3457 LoadedFeature *feature;
3458 int i;
3460 if (!ShapingData[psa->eScript].requiredFeatures)
3461 return S_OK;
3463 load_ot_tables(hdc, psc);
3465 /* we need to have at least one of the required features */
3466 i = 0;
3467 while (ShapingData[psa->eScript].requiredFeatures[i])
3469 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3470 if (feature)
3471 return S_OK;
3472 i++;
3475 return USP_E_SCRIPT_NOT_IN_FONT;
3478 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3479 SCRIPT_ANALYSIS *psa, int cMaxTags,
3480 OPENTYPE_TAG *pScriptTags, int *pcTags)
3482 HRESULT hr;
3483 OPENTYPE_TAG searching = 0x00000000;
3485 load_ot_tables(hdc, psc);
3487 if (psa && scriptInformation[psa->eScript].scriptTag)
3488 searching = scriptInformation[psa->eScript].scriptTag;
3490 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3491 if (FAILED(hr))
3492 *pcTags = 0;
3493 return hr;
3496 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3497 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3498 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3499 int *pcTags)
3501 HRESULT hr;
3502 OPENTYPE_TAG searching = 0x00000000;
3503 BOOL fellback = FALSE;
3505 load_ot_tables(hdc, psc);
3507 if (psa && psc->userLang != 0)
3508 searching = psc->userLang;
3510 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3511 if (FAILED(hr))
3513 fellback = TRUE;
3514 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3517 if (FAILED(hr) || fellback)
3518 *pcTags = 0;
3519 if (SUCCEEDED(hr) && fellback && psa)
3520 hr = E_INVALIDARG;
3521 return hr;
3524 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3525 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3526 OPENTYPE_TAG tagLangSys, int cMaxTags,
3527 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3529 HRESULT hr;
3530 BOOL filter = FALSE;
3532 load_ot_tables(hdc, psc);
3534 if (psa && scriptInformation[psa->eScript].scriptTag)
3536 FIXME("Filtering not implemented\n");
3537 filter = TRUE;
3540 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3542 if (FAILED(hr))
3543 *pcTags = 0;
3544 return hr;