po: Update Lithuanian translation.
[wine.git] / dlls / usp10 / shape.c
blob3827000122a75a76d959238d4ae59f3aece4ede0
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 += 2)
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;
1727 static void Reorder_Ra_follows_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1729 if (s->ralf >= 0)
1731 int j;
1732 WORD Ra = pwChar[s->start];
1733 WORD H = pwChar[s->start+1];
1735 TRACE("Doing reorder of Ra to %i\n",s->base);
1736 for (j = s->start; j < s->base-1; j++)
1737 pwChar[j] = pwChar[j+2];
1738 pwChar[s->base-1] = Ra;
1739 pwChar[s->base] = H;
1741 s->ralf = s->base-1;
1742 s->base -= 2;
1746 static void Reorder_Ra_follows_matra(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1748 if (s->ralf >= 0)
1750 int j,loc;
1751 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1752 WORD Ra = pwChar[s->start];
1753 WORD H = pwChar[s->start+1];
1754 for (loc = s->end; loc > stop; loc--)
1755 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1756 break;
1758 TRACE("Doing reorder of Ra to %i\n",loc);
1759 for (j = s->start; j < loc-1; j++)
1760 pwChar[j] = pwChar[j+2];
1761 pwChar[loc-1] = Ra;
1762 pwChar[loc] = H;
1764 s->ralf = loc-1;
1765 s->base -= 2;
1766 if (s->blwf >= 0) s->blwf -= 2;
1767 if (s->pref >= 0) s->pref -= 2;
1771 static void Reorder_Ra_follows_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1773 if (s->ralf >= 0)
1775 int j;
1776 WORD Ra = pwChar[s->start];
1777 WORD H = pwChar[s->start+1];
1779 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1780 for (j = s->start; j < s->end-1; j++)
1781 pwChar[j] = pwChar[j+2];
1782 pwChar[s->end-1] = Ra;
1783 pwChar[s->end] = H;
1785 s->ralf = s->end-1;
1786 s->base -= 2;
1787 if (s->blwf >= 0) s->blwf -= 2;
1788 if (s->pref >= 0) s->pref -= 2;
1792 static void Reorder_Matra_precede_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1794 int i;
1796 /* reorder Matras */
1797 if (s->end > s->base)
1799 for (i = 1; i <= s->end-s->base; i++)
1801 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1803 int j;
1804 WCHAR c = pwChar[s->base+i];
1805 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1806 for (j = s->base+i; j > s->base; j--)
1807 pwChar[j] = pwChar[j-1];
1808 pwChar[s->base] = c;
1810 if (s->ralf >= s->base) s->ralf++;
1811 if (s->blwf >= s->base) s->blwf++;
1812 if (s->pref >= s->base) s->pref++;
1813 s->base ++;
1819 static void Reorder_Matra_precede_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1821 int i;
1823 /* reorder Matras */
1824 if (s->end > s->base)
1826 for (i = 1; i <= s->end-s->base; i++)
1828 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1830 int j;
1831 WCHAR c = pwChar[s->base+i];
1832 TRACE("Doing reorder of %x to %i\n",c,s->start);
1833 for (j = s->base+i; j > s->start; j--)
1834 pwChar[j] = pwChar[j-1];
1835 pwChar[s->start] = c;
1837 if (s->ralf >= 0) s->ralf++;
1838 if (s->blwf >= 0) s->blwf++;
1839 if (s->pref >= 0) s->pref++;
1840 s->base ++;
1846 static void SecondReorder_Blwf_follows_matra(const WCHAR *chars, const IndicSyllable *s,
1847 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1849 if (s->blwf >= 0 && g->blwf > g->base)
1851 int j,loc;
1852 int g_offset;
1853 for (loc = s->end; loc > s->blwf; loc--)
1854 if (lexical(chars[loc]) == lex_Matra_below || lexical(chars[loc]) == lex_Matra_above
1855 || lexical(chars[loc]) == lex_Matra_post)
1856 break;
1858 g_offset = (loc - s->blwf) - 1;
1860 if (loc != s->blwf)
1862 WORD blwf = glyphs[g->blwf];
1863 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1864 /* do not care about the pwChar array anymore, just the glyphs */
1865 for (j = 0; j < g_offset; j++)
1866 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1867 glyphs[g->blwf + g_offset] = blwf;
1872 static void SecondReorder_Matra_precede_base(const WCHAR *chars, const IndicSyllable *s,
1873 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1875 int i;
1877 /* reorder previously moved Matras to correct position*/
1878 for (i = s->start; i < s->base; i++)
1880 if (lexical(chars[i]) == lex_Matra_pre)
1882 int j;
1883 int g_start = g->start + i - s->start;
1884 if (g_start < g->base -1 )
1886 WCHAR og = glyphs[g_start];
1887 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1888 for (j = g_start; j < g->base-1; j++)
1889 glyphs[j] = glyphs[j+1];
1890 glyphs[g->base-1] = og;
1896 static void SecondReorder_Pref_precede_base(const IndicSyllable *s,
1897 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1899 if (s->pref >= 0 && g->pref > g->base)
1901 int j;
1902 WCHAR og = glyphs[g->pref];
1903 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1904 for (j = g->pref; j > g->base; j--)
1905 glyphs[j] = glyphs[j-1];
1906 glyphs[g->base] = og;
1910 static void Reorder_Like_Sinhala(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1912 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1913 if (s->start == s->base && s->base == s->end) return;
1914 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1916 Reorder_Ra_follows_base(pwChar, s, lexical);
1917 Reorder_Matra_precede_base(pwChar, s, lexical);
1920 static void Reorder_Like_Devanagari(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1922 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1923 if (s->start == s->base && s->base == s->end) return;
1924 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1926 Reorder_Ra_follows_matra(pwChar, s, lexical);
1927 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1930 static void Reorder_Like_Bengali(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1932 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1933 if (s->start == s->base && s->base == s->end) return;
1934 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1936 Reorder_Ra_follows_base(pwChar, s, lexical);
1937 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1940 static void Reorder_Like_Kannada(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1942 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1943 if (s->start == s->base && s->base == s->end) return;
1944 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1946 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1947 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1950 static void SecondReorder_Like_Telugu(const WCHAR *chars, const IndicSyllable *s,
1951 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1953 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1954 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1955 if (s->start == s->base && s->base == s->end) return;
1956 if (lexical(chars[s->base]) == lex_Vowel) return;
1958 SecondReorder_Blwf_follows_matra(chars, s, glyphs, g, lexical);
1961 static void SecondReorder_Like_Tamil(const WCHAR *chars, const IndicSyllable *s,
1962 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1964 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1965 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1966 if (s->start == s->base && s->base == s->end) return;
1967 if (lexical(chars[s->base]) == lex_Vowel) return;
1969 SecondReorder_Matra_precede_base(chars, s, glyphs, g, lexical);
1970 SecondReorder_Pref_precede_base(s, glyphs, g, lexical);
1974 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1976 if (shift == 0)
1977 return;
1979 if (glyph_index->start > index)
1980 glyph_index->start += shift;
1981 if (glyph_index->base > index)
1982 glyph_index->base+= shift;
1983 if (glyph_index->end > index)
1984 glyph_index->end+= shift;
1985 if (glyph_index->ralf > index)
1986 glyph_index->ralf+= shift;
1987 if (glyph_index->blwf > index)
1988 glyph_index->blwf+= shift;
1989 if (glyph_index->pref > index)
1990 glyph_index->pref+= shift;
1993 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 )
1995 int index = glyph_index->start;
1997 if (!feature)
1998 return;
2000 while(index <= glyph_index->end)
2002 INT nextIndex;
2003 INT prevCount = *pcGlyphs;
2004 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2005 if (nextIndex > GSUB_E_NOGLYPH)
2007 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2008 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2009 index = nextIndex;
2011 else
2012 index++;
2016 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2018 int i = 0;
2019 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)))))
2020 i++;
2021 if (index + i <= end-1)
2022 return index + i;
2023 else
2024 return -1;
2027 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)
2029 INT index, nextIndex;
2030 INT count,g_offset;
2032 count = syllable->base - syllable->start;
2034 g_offset = 0;
2035 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2036 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2038 INT prevCount = *pcGlyphs;
2039 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2040 if (nextIndex > GSUB_E_NOGLYPH)
2042 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2043 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2044 g_offset += (*pcGlyphs - prevCount);
2047 index+=2;
2048 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2052 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)
2054 INT nextIndex;
2055 INT prevCount = *pcGlyphs;
2057 if (syllable->ralf >= 0)
2059 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2060 if (nextIndex > GSUB_E_NOGLYPH)
2062 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2063 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2068 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2070 int i = 0;
2071 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2072 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2073 is_consonant(lexical(pwChars[index+i+1])))))
2074 i++;
2075 if (index + i <= end-1)
2076 return index+i;
2077 else
2078 return -1;
2081 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)
2083 INT index, nextIndex;
2084 INT count, g_offset=0;
2085 INT ralf = syllable->ralf;
2087 count = syllable->end - syllable->base;
2089 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2091 while (index >= 0)
2093 INT prevCount = *pcGlyphs;
2094 if (ralf >=0 && ralf < index)
2096 g_offset--;
2097 ralf = -1;
2100 if (!modern)
2102 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2103 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2104 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2107 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2108 if (nextIndex > GSUB_E_NOGLYPH)
2110 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2111 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2112 g_offset += (*pcGlyphs - prevCount);
2114 else if (!modern)
2116 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2117 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2118 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2121 index+=2;
2122 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2126 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)
2128 int c;
2129 int overall_shift = 0;
2130 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2131 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2132 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2133 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2134 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2135 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2136 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2137 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2138 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2139 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2140 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2141 IndicSyllable glyph_indexs;
2143 for (c = 0; c < syllable_count; c++)
2145 int old_end;
2146 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2147 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2148 old_end = glyph_indexs.end;
2150 if (locl)
2152 TRACE("applying feature locl\n");
2153 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2155 if (nukt)
2157 TRACE("applying feature nukt\n");
2158 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2160 if (akhn)
2162 TRACE("applying feature akhn\n");
2163 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2166 if (rphf)
2167 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2168 if (rkrf)
2170 TRACE("applying feature rkrf\n");
2171 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2173 if (pref)
2174 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2175 if (blwf)
2177 if (!modern)
2178 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2180 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2183 if (half)
2184 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2185 if (pstf)
2187 TRACE("applying feature pstf\n");
2188 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2190 if (vatu)
2192 TRACE("applying feature vatu\n");
2193 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2195 if (cjct)
2197 TRACE("applying feature cjct\n");
2198 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2201 if (second_reorder)
2202 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2204 overall_shift += glyph_indexs.end - old_end;
2208 static inline int unicode_lex(WCHAR c)
2210 int type;
2212 if (!c) return lex_Generic;
2213 if (c == 0x200D) return lex_ZWJ;
2214 if (c == 0x200C) return lex_ZWNJ;
2215 if (c == 0x00A0) return lex_NBSP;
2217 type = get_table_entry( indic_syllabic_table, c );
2219 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2221 switch( type )
2223 case 0x0d07: /* Unknown */
2224 case 0x0e07: /* Unknown */
2225 default: return lex_Generic;
2226 case 0x0001:
2227 case 0x0002:
2228 case 0x0011:
2229 case 0x0012:
2230 case 0x0013:
2231 case 0x0014: return lex_Modifier;
2232 case 0x0003:
2233 case 0x0009:
2234 case 0x000a:
2235 case 0x000b:
2236 case 0x000d:
2237 case 0x000e:
2238 case 0x000f:
2239 case 0x0010: return lex_Consonant;
2240 case 0x0004: return lex_Nukta;
2241 case 0x0005: return lex_Halant;
2242 case 0x0006:
2243 case 0x0008: return lex_Vowel;
2244 case 0x0007:
2245 case 0x0107: return lex_Matra_post;
2246 case 0x0207:
2247 case 0x0307: return lex_Matra_pre;
2248 case 0x0807:
2249 case 0x0907:
2250 case 0x0a07:
2251 case 0x0b07:
2252 case 0x0c07:
2253 case 0x0407: return lex_Composed_Vowel;
2254 case 0x0507: return lex_Matra_above;
2255 case 0x0607: return lex_Matra_below;
2256 case 0x000c:
2257 case 0x0015: return lex_Ra;
2261 static int sinhala_lex(WCHAR c)
2263 switch (c)
2265 case 0x0DDA:
2266 case 0x0DDD:
2267 case 0x0DDC:
2268 case 0x0DDE: return lex_Matra_post;
2269 default:
2270 return unicode_lex(c);
2274 static const VowelComponents Sinhala_vowels[] = {
2275 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2276 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2277 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2278 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2279 {0x0000, {0x0000,0x0000,0x0}}};
2281 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2283 int cCount = cChars;
2284 int i;
2285 WCHAR *input;
2286 IndicSyllable *syllables = NULL;
2287 int syllable_count = 0;
2289 if (*pcGlyphs != cChars)
2291 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2292 return;
2295 input = heap_alloc(3 * cChars * sizeof(*input));
2297 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2299 /* Step 1: Decompose multi part vowels */
2300 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2302 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2304 /* Step 2: Reorder within Syllables */
2305 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2306 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2308 /* Step 3: Strip dangling joiners */
2309 for (i = 0; i < cCount; i++)
2311 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2312 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2313 input[i] = 0x0020;
2316 /* Step 4: Base Form application to syllables */
2317 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2318 *pcGlyphs = cCount;
2319 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2321 heap_free(input);
2322 heap_free(syllables);
2325 static int devanagari_lex(WCHAR c)
2327 switch (c)
2329 case 0x0930: return lex_Ra;
2330 default:
2331 return unicode_lex(c);
2335 static const ConsonantComponents Devanagari_consonants[] ={
2336 {{0x0928, 0x093C, 0x00000}, 0x0929},
2337 {{0x0930, 0x093C, 0x00000}, 0x0931},
2338 {{0x0933, 0x093C, 0x00000}, 0x0934},
2339 {{0x0915, 0x093C, 0x00000}, 0x0958},
2340 {{0x0916, 0x093C, 0x00000}, 0x0959},
2341 {{0x0917, 0x093C, 0x00000}, 0x095A},
2342 {{0x091C, 0x093C, 0x00000}, 0x095B},
2343 {{0x0921, 0x093C, 0x00000}, 0x095C},
2344 {{0x0922, 0x093C, 0x00000}, 0x095D},
2345 {{0x092B, 0x093C, 0x00000}, 0x095E},
2346 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2348 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2350 int cCount = cChars;
2351 WCHAR *input;
2352 IndicSyllable *syllables = NULL;
2353 int syllable_count = 0;
2354 BOOL modern = get_GSUB_Indic2(psa, psc);
2356 if (*pcGlyphs != cChars)
2358 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2359 return;
2362 input = heap_alloc(cChars * sizeof(*input));
2363 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2365 /* Step 1: Compose Consonant and Nukta */
2366 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2367 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2369 /* Step 2: Reorder within Syllables */
2370 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2371 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2372 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2373 *pcGlyphs = cCount;
2375 /* Step 3: Base Form application to syllables */
2376 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2378 heap_free(input);
2379 heap_free(syllables);
2382 static int bengali_lex(WCHAR c)
2384 switch (c)
2386 case 0x09B0: return lex_Ra;
2387 default:
2388 return unicode_lex(c);
2392 static const VowelComponents Bengali_vowels[] = {
2393 {0x09CB, {0x09C7,0x09BE,0x0000}},
2394 {0x09CC, {0x09C7,0x09D7,0x0000}},
2395 {0x0000, {0x0000,0x0000,0x0000}}};
2397 static const ConsonantComponents Bengali_consonants[] = {
2398 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2399 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2400 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2401 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2402 {{0x0000,0x0000,0x0000}, 0x0000}};
2404 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2406 int cCount = cChars;
2407 WCHAR *input;
2408 IndicSyllable *syllables = NULL;
2409 int syllable_count = 0;
2410 BOOL modern = get_GSUB_Indic2(psa, psc);
2412 if (*pcGlyphs != cChars)
2414 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2415 return;
2418 input = heap_alloc(2 * cChars * sizeof(*input));
2419 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2421 /* Step 1: Decompose Vowels and Compose Consonants */
2422 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2423 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2424 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2426 /* Step 2: Reorder within Syllables */
2427 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2428 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2429 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2430 *pcGlyphs = cCount;
2432 /* Step 3: Initial form is only applied to the beginning of words */
2433 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2435 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2437 int index = cCount;
2438 int gCount = 1;
2439 if (index > 0) index++;
2441 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2445 /* Step 4: Base Form application to syllables */
2446 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2448 heap_free(input);
2449 heap_free(syllables);
2452 static int gurmukhi_lex(WCHAR c)
2454 if (c == 0x0A71)
2455 return lex_Modifier;
2456 else
2457 return unicode_lex(c);
2460 static const ConsonantComponents Gurmukhi_consonants[] = {
2461 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2462 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2463 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2464 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2465 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2466 {{0x0000,0x0000,0x0000}, 0x0000}};
2468 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2470 int cCount = cChars;
2471 WCHAR *input;
2472 IndicSyllable *syllables = NULL;
2473 int syllable_count = 0;
2474 BOOL modern = get_GSUB_Indic2(psa, psc);
2476 if (*pcGlyphs != cChars)
2478 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2479 return;
2482 input = heap_alloc(cChars * sizeof(*input));
2483 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2485 /* Step 1: Compose Consonants */
2486 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2487 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2489 /* Step 2: Reorder within Syllables */
2490 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2491 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2492 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2493 *pcGlyphs = cCount;
2495 /* Step 3: Base Form application to syllables */
2496 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2498 heap_free(input);
2499 heap_free(syllables);
2502 static int gujarati_lex(WCHAR c)
2504 switch (c)
2506 case 0x0AB0: return lex_Ra;
2507 default:
2508 return unicode_lex(c);
2512 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2514 int cCount = cChars;
2515 WCHAR *input;
2516 IndicSyllable *syllables = NULL;
2517 int syllable_count = 0;
2518 BOOL modern = get_GSUB_Indic2(psa, psc);
2520 if (*pcGlyphs != cChars)
2522 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2523 return;
2526 input = heap_alloc(cChars * sizeof(*input));
2527 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2529 /* Step 1: Reorder within Syllables */
2530 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2531 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2532 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2533 *pcGlyphs = cCount;
2535 /* Step 2: Base Form application to syllables */
2536 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2538 heap_free(input);
2539 heap_free(syllables);
2542 static int oriya_lex(WCHAR c)
2544 switch (c)
2546 case 0x0B30: return lex_Ra;
2547 default:
2548 return unicode_lex(c);
2552 static const VowelComponents Oriya_vowels[] = {
2553 {0x0B48, {0x0B47,0x0B56,0x0000}},
2554 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2555 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2556 {0x0000, {0x0000,0x0000,0x0000}}};
2558 static const ConsonantComponents Oriya_consonants[] = {
2559 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2560 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2561 {{0x0000,0x0000,0x0000}, 0x0000}};
2563 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2565 int cCount = cChars;
2566 WCHAR *input;
2567 IndicSyllable *syllables = NULL;
2568 int syllable_count = 0;
2569 BOOL modern = get_GSUB_Indic2(psa, psc);
2571 if (*pcGlyphs != cChars)
2573 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2574 return;
2577 input = heap_alloc(2 * cChars * sizeof(*input));
2578 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2580 /* Step 1: Decompose Vowels and Compose Consonants */
2581 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2582 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2583 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2585 /* Step 2: Reorder within Syllables */
2586 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2587 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2588 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2589 *pcGlyphs = cCount;
2591 /* Step 3: Base Form application to syllables */
2592 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2594 heap_free(input);
2595 heap_free(syllables);
2598 static int tamil_lex(WCHAR c)
2600 return unicode_lex(c);
2603 static const VowelComponents Tamil_vowels[] = {
2604 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2605 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2606 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2607 {0x0000, {0x0000,0x0000,0x0000}}};
2609 static const ConsonantComponents Tamil_consonants[] = {
2610 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2611 {{0x0000,0x0000,0x0000}, 0x0000}};
2613 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2615 int cCount = cChars;
2616 WCHAR *input;
2617 IndicSyllable *syllables = NULL;
2618 int syllable_count = 0;
2619 BOOL modern = get_GSUB_Indic2(psa, psc);
2621 if (*pcGlyphs != cChars)
2623 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2624 return;
2627 input = heap_alloc(2 * cChars * sizeof(*input));
2628 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2630 /* Step 1: Decompose Vowels and Compose Consonants */
2631 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2632 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2633 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2635 /* Step 2: Reorder within Syllables */
2636 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2637 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2638 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2639 *pcGlyphs = cCount;
2641 /* Step 3: Base Form application to syllables */
2642 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2644 heap_free(input);
2645 heap_free(syllables);
2648 static int telugu_lex(WCHAR c)
2650 switch (c)
2652 case 0x0C43:
2653 case 0x0C44: return lex_Modifier;
2654 default:
2655 return unicode_lex(c);
2659 static const VowelComponents Telugu_vowels[] = {
2660 {0x0C48, {0x0C46,0x0C56,0x0000}},
2661 {0x0000, {0x0000,0x0000,0x0000}}};
2663 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2665 int cCount = cChars;
2666 WCHAR *input;
2667 IndicSyllable *syllables = NULL;
2668 int syllable_count = 0;
2669 BOOL modern = get_GSUB_Indic2(psa, psc);
2671 if (*pcGlyphs != cChars)
2673 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2674 return;
2677 input = heap_alloc(2 * cChars * sizeof(*input));
2678 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2680 /* Step 1: Decompose Vowels */
2681 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2682 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2684 /* Step 2: Reorder within Syllables */
2685 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2686 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2687 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2688 *pcGlyphs = cCount;
2690 /* Step 3: Base Form application to syllables */
2691 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2693 heap_free(input);
2694 heap_free(syllables);
2697 static int kannada_lex(WCHAR c)
2699 switch (c)
2701 case 0x0CB0: return lex_Ra;
2702 default:
2703 return unicode_lex(c);
2707 static const VowelComponents Kannada_vowels[] = {
2708 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2709 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2710 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2711 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2712 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2713 {0x0000, {0x0000,0x0000,0x0000}}};
2715 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2717 int cCount = cChars;
2718 WCHAR *input;
2719 IndicSyllable *syllables = NULL;
2720 int syllable_count = 0;
2721 BOOL modern = get_GSUB_Indic2(psa, psc);
2723 if (*pcGlyphs != cChars)
2725 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2726 return;
2729 input = heap_alloc(3 * cChars * sizeof(*input));
2730 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2732 /* Step 1: Decompose Vowels */
2733 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2734 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2736 /* Step 2: Reorder within Syllables */
2737 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2738 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2739 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2740 *pcGlyphs = cCount;
2742 /* Step 3: Base Form application to syllables */
2743 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2745 heap_free(input);
2746 heap_free(syllables);
2749 static int malayalam_lex(WCHAR c)
2751 return unicode_lex(c);
2754 static const VowelComponents Malayalam_vowels[] = {
2755 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2756 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2757 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2758 {0x0000, {0x0000,0x0000,0x0000}}};
2760 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2762 int cCount = cChars;
2763 WCHAR *input;
2764 IndicSyllable *syllables = NULL;
2765 int syllable_count = 0;
2766 BOOL modern = get_GSUB_Indic2(psa, psc);
2768 if (*pcGlyphs != cChars)
2770 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2771 return;
2774 input = heap_alloc(2 * cChars * sizeof(*input));
2775 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2777 /* Step 1: Decompose Vowels */
2778 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2779 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2781 /* Step 2: Reorder within Syllables */
2782 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2783 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2784 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2785 *pcGlyphs = cCount;
2787 /* Step 3: Base Form application to syllables */
2788 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2790 heap_free(input);
2791 heap_free(syllables);
2794 static int khmer_lex(WCHAR c)
2796 return unicode_lex(c);
2799 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2801 int cCount = cChars;
2802 WCHAR *input;
2803 IndicSyllable *syllables = NULL;
2804 int syllable_count = 0;
2806 if (*pcGlyphs != cChars)
2808 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2809 return;
2812 input = heap_alloc(cChars * sizeof(*input));
2813 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2815 /* Step 1: Reorder within Syllables */
2816 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2817 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2818 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2819 *pcGlyphs = cCount;
2821 /* Step 2: Base Form application to syllables */
2822 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2824 heap_free(input);
2825 heap_free(syllables);
2828 static inline BOOL mongolian_wordbreak(WCHAR chr)
2830 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2833 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2835 INT *context_shape;
2836 INT dirL;
2837 int i;
2838 int char_index;
2839 int glyph_index;
2841 if (*pcGlyphs != cChars)
2843 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2844 return;
2847 if (!psa->fLogicalOrder && psa->fRTL)
2848 dirL = -1;
2849 else
2850 dirL = 1;
2852 if (!psc->GSUB_Table)
2853 return;
2855 context_shape = heap_alloc(cChars * sizeof(*context_shape));
2857 for (i = 0; i < cChars; i++)
2859 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2861 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2862 context_shape[i] = Xn;
2863 else
2864 context_shape[i] = Xl;
2866 else
2868 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2869 context_shape[i] = Xr;
2870 else
2871 context_shape[i] = Xm;
2875 /* Contextual Shaping */
2876 if (dirL > 0)
2877 char_index = glyph_index = 0;
2878 else
2879 char_index = glyph_index = cChars-1;
2881 while(char_index < cChars && char_index >= 0)
2883 INT nextIndex;
2884 INT prevCount = *pcGlyphs;
2885 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2887 if (nextIndex > GSUB_E_NOGLYPH)
2889 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2890 glyph_index = nextIndex;
2891 char_index += dirL;
2893 else
2895 char_index += dirL;
2896 glyph_index += dirL;
2900 heap_free(context_shape);
2903 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)
2905 int i,k;
2907 for (i = 0; i < cGlyphs; i++)
2909 int char_index[20];
2910 int char_count = 0;
2912 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2913 if (k>=0)
2915 for (; k < cChars && pwLogClust[k] == i; k++)
2916 char_index[char_count++] = k;
2919 if (char_count == 0)
2920 continue;
2922 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2924 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2925 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2927 else
2928 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2931 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2932 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2935 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 )
2937 int i;
2939 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2941 for (i = 0; i < cGlyphs; i++)
2942 if (pGlyphProp[i].sva.fZeroWidth)
2943 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2946 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 )
2948 int i;
2949 for (i = 0; i < cGlyphs; i++)
2951 pGlyphProp[i].sva.fClusterStart = 1;
2952 pGlyphProp[i].sva.fDiacritic = 0;
2953 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2955 if (pwGlyphs[i] == psc->sfp.wgDefault)
2956 pGlyphProp[i].sva.fZeroWidth = 0;
2957 else
2958 pGlyphProp[i].sva.fZeroWidth = 1;
2962 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 )
2964 int i,k;
2965 int initGlyph, finaGlyph;
2966 INT dirR, dirL;
2967 BYTE *spaces;
2969 spaces = heap_alloc(cGlyphs);
2970 memset(spaces,0,cGlyphs);
2972 if (psa->fLogicalOrder && psa->fRTL)
2974 initGlyph = 0;
2975 finaGlyph = cGlyphs-1;
2976 dirR = -1;
2977 dirL = 1;
2979 else
2981 initGlyph = cGlyphs-1;
2982 finaGlyph = 0;
2983 dirR = 1;
2984 dirL = -1;
2987 for (i = 0; i < cGlyphs; i++)
2989 for (k = 0; k < cChars; k++)
2990 if (pwLogClust[k] == i)
2992 if (pwcChars[k] == 0x0020)
2993 spaces[i] = 1;
2997 for (i = 0; i < cGlyphs; i++)
2999 int char_index[20];
3000 int char_count = 0;
3001 BOOL isInit, isFinal;
3003 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3004 if (k>=0)
3006 for (; k < cChars && pwLogClust[k] == i; k++)
3007 char_index[char_count++] = k;
3010 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3011 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3013 if (char_count == 0)
3014 continue;
3016 if (char_count == 1)
3018 if (pwcChars[char_index[0]] == 0x0020) /* space */
3020 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3021 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3023 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3024 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3025 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3027 if (!isInit && !isFinal)
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3029 else if (isInit)
3030 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3031 else
3032 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3034 else if (!isInit)
3036 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3037 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3038 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3039 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3040 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3041 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3042 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3043 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3044 else
3045 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3047 else if (!isInit && !isFinal)
3048 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3049 else
3050 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3052 else if (char_count == 2)
3054 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3056 else if (!isInit)
3057 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3058 else
3059 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3061 else if (!isInit && !isFinal)
3062 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3063 else
3064 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3067 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3068 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3069 heap_free(spaces);
3072 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 )
3074 int i,k;
3076 for (i = 0; i < cGlyphs; i++)
3078 int char_index[20];
3079 int char_count = 0;
3081 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3082 if (k>=0)
3084 for (; k < cChars && pwLogClust[k] == i; k++)
3085 char_index[char_count++] = k;
3088 if (char_count == 0)
3089 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3090 else
3092 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3093 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3094 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3098 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3099 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3102 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 )
3104 int i;
3105 int finaGlyph;
3106 INT dirL;
3108 if (!psa->fLogicalOrder && psa->fRTL)
3110 finaGlyph = 0;
3111 dirL = -1;
3113 else
3115 finaGlyph = cGlyphs-1;
3116 dirL = 1;
3119 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3121 for (i = 0; i < cGlyphs; i++)
3123 int k;
3124 int char_index[20];
3125 int char_count = 0;
3127 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3128 if (k>=0)
3130 for (; k < cChars && pwLogClust[k] == i; k++)
3131 char_index[char_count++] = k;
3134 if (i == finaGlyph)
3135 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3136 else
3137 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3139 if (char_count == 0)
3140 continue;
3142 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3143 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3145 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3146 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3147 pGlyphProp[i].sva.fClusterStart = 0;
3150 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3152 /* Do not allow justification between marks and their base */
3153 for (i = 0; i < cGlyphs; i++)
3155 if (!pGlyphProp[i].sva.fClusterStart)
3156 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3160 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)
3162 int i,k;
3164 for (i = 0; i < cGlyphs; i++)
3166 int char_index[20];
3167 int char_count = 0;
3169 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3170 if (k>=0)
3172 for (; k < cChars && pwLogClust[k] == i; k++)
3173 char_index[char_count++] = k;
3176 if (char_count == 0)
3177 continue;
3179 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3181 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3182 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3184 else
3185 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3187 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3188 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3191 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)
3193 int i,k;
3195 for (i = 0; i < cGlyphs; i++)
3197 int char_index[20];
3198 int char_count = 0;
3200 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3201 if (k>=0)
3203 for (; k < cChars && pwLogClust[k] == i; k++)
3204 char_index[char_count++] = k;
3207 if (char_count == 0)
3208 continue;
3210 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3212 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3213 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3215 else
3216 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3218 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3219 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3221 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3222 for (i = 0; i < cGlyphs; i++)
3224 if (!pGlyphProp[i].sva.fClusterStart)
3226 pGlyphProp[i].sva.fDiacritic = 0;
3227 pGlyphProp[i].sva.fZeroWidth = 0;
3232 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)
3234 int i,k;
3236 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3237 for (i = 0; i < cGlyphs; i++)
3239 int char_index[20];
3240 int char_count = 0;
3242 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3243 if (k>=0)
3245 for (; k < cChars && pwLogClust[k] == i; k++)
3246 char_index[char_count++] = k;
3249 if (override_gsub)
3251 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3252 pGlyphProp[i].sva.fDiacritic = FALSE;
3253 pGlyphProp[i].sva.fZeroWidth = FALSE;
3256 if (char_count == 0)
3258 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3259 continue;
3262 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3264 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3265 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3267 else
3268 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3270 pGlyphProp[i].sva.fClusterStart = 0;
3271 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3272 switch (lexical(pwcChars[char_index[k]]))
3274 case lex_Matra_pre:
3275 case lex_Matra_post:
3276 case lex_Matra_above:
3277 case lex_Matra_below:
3278 case lex_Modifier:
3279 case lex_Halant:
3280 break;
3281 case lex_ZWJ:
3282 case lex_ZWNJ:
3283 /* check for dangling joiners */
3284 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3285 pGlyphProp[i].sva.fClusterStart = 1;
3286 else
3287 k = char_count;
3288 break;
3289 default:
3290 pGlyphProp[i].sva.fClusterStart = 1;
3291 break;
3295 if (use_syllables)
3297 IndicSyllable *syllables = NULL;
3298 int syllable_count = 0;
3299 BOOL modern = get_GSUB_Indic2(psa, psc);
3301 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3303 for (i = 0; i < syllable_count; i++)
3305 int j;
3306 WORD g = pwLogClust[syllables[i].start];
3307 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3309 if (pwLogClust[j] != g)
3311 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3312 pwLogClust[j] = g;
3317 heap_free(syllables);
3320 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3323 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 )
3325 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3328 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 )
3330 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3333 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 )
3335 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3338 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 )
3340 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3343 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 )
3345 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3348 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 )
3350 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3353 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 )
3355 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3358 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 )
3360 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3363 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 )
3365 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3368 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 )
3370 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3373 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 )
3375 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3378 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)
3380 load_ot_tables(hdc, psc);
3382 if (ShapingData[psa->eScript].charGlyphPropProc)
3383 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3384 else
3385 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3388 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3390 load_ot_tables(hdc, psc);
3392 if (ShapingData[psa->eScript].contextProc)
3393 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3396 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)
3398 int i;
3399 INT dirL;
3401 if (!rpRangeProperties)
3402 return;
3404 load_ot_tables(hdc, psc);
3406 if (!psc->GSUB_Table)
3407 return;
3409 if (scriptInformation[psa->eScript].a.fRTL && (!psa->fLogicalOrder || !psa->fRTL))
3410 dirL = -1;
3411 else
3412 dirL = 1;
3414 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3416 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3417 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3421 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3423 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3424 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3426 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3429 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3431 const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3432 int i;
3434 load_ot_tables(hdc, psc);
3436 if (!psc->GPOS_Table || !psc->otm)
3437 return;
3439 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3441 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3443 LoadedFeature *feature;
3445 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3446 if (!feature)
3447 continue;
3449 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3454 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3456 LoadedFeature *feature;
3457 int i;
3459 if (!ShapingData[psa->eScript].requiredFeatures)
3460 return S_OK;
3462 load_ot_tables(hdc, psc);
3464 /* we need to have at least one of the required features */
3465 i = 0;
3466 while (ShapingData[psa->eScript].requiredFeatures[i])
3468 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3469 if (feature)
3470 return S_OK;
3471 i++;
3474 return USP_E_SCRIPT_NOT_IN_FONT;
3477 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3478 SCRIPT_ANALYSIS *psa, int cMaxTags,
3479 OPENTYPE_TAG *pScriptTags, int *pcTags)
3481 HRESULT hr;
3482 OPENTYPE_TAG searching = 0x00000000;
3484 load_ot_tables(hdc, psc);
3486 if (psa && scriptInformation[psa->eScript].scriptTag)
3487 searching = scriptInformation[psa->eScript].scriptTag;
3489 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3490 if (FAILED(hr))
3491 *pcTags = 0;
3492 return hr;
3495 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3496 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3497 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3498 int *pcTags)
3500 HRESULT hr;
3501 OPENTYPE_TAG searching = 0x00000000;
3502 BOOL fellback = FALSE;
3504 load_ot_tables(hdc, psc);
3506 if (psa && psc->userLang != 0)
3507 searching = psc->userLang;
3509 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3510 if (FAILED(hr))
3512 fellback = TRUE;
3513 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3516 if (FAILED(hr) || fellback)
3517 *pcTags = 0;
3518 if (SUCCEEDED(hr) && fellback && psa)
3519 hr = E_INVALIDARG;
3520 return hr;
3523 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3524 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3525 OPENTYPE_TAG tagLangSys, int cMaxTags,
3526 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3528 HRESULT hr;
3529 BOOL filter = FALSE;
3531 load_ot_tables(hdc, psc);
3533 if (psa && scriptInformation[psa->eScript].scriptTag)
3535 FIXME("Filtering not implemented\n");
3536 filter = TRUE;
3539 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3541 if (FAILED(hr))
3542 *pcTags = 0;
3543 return hr;