usp10: Only fall back to latin features if the base script tag is not found at all.
[wine.git] / dlls / usp10 / shape.c
blobe40a404b733141f9dda6896e2058ff43c34695c7
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #define FIRST_ARABIC_CHAR 0x0600
39 #define LAST_ARABIC_CHAR 0x06ff
41 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
42 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
64 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
66 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
67 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
68 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
73 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
75 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
76 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
77 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
78 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
79 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
80 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
81 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
82 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
84 extern const unsigned short indic_syllabic_table[];
85 extern const unsigned short wine_shaping_table[];
86 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
88 enum joining_types {
89 jtU,
90 jtT,
91 jtR,
92 jtL,
93 jtD,
94 jtC
97 enum joined_forms {
98 Xn=0,
99 Xr,
102 /* Syriac Alaph */
103 Afj,
104 Afn,
108 typedef struct tagVowelComponents
110 WCHAR base;
111 WCHAR parts[3];
112 } VowelComponents;
114 typedef struct tagConsonantComponents
116 WCHAR parts[3];
117 WCHAR output;
118 } ConsonantComponents;
120 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
122 typedef int (*combining_lexical_function)(WCHAR c);
124 /* the orders of joined_forms and contextual_features need to line up */
125 static const char* contextual_features[] =
127 "isol",
128 "fina",
129 "init",
130 "medi",
131 /* Syriac Alaph */
132 "med2",
133 "fin2",
134 "fin3"
137 static OPENTYPE_FEATURE_RECORD standard_features[] =
139 { MS_MAKE_TAG('c','c','m','p'), 1},
140 { MS_MAKE_TAG('l','o','c','l'), 1},
143 static OPENTYPE_FEATURE_RECORD latin_features[] =
145 { MS_MAKE_TAG('l','o','c','l'), 1},
146 { MS_MAKE_TAG('c','c','m','p'), 1},
147 { MS_MAKE_TAG('l','i','g','a'), 1},
148 { MS_MAKE_TAG('c','l','i','g'), 1},
151 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
153 { MS_MAKE_TAG('k','e','r','n'), 1},
154 { MS_MAKE_TAG('m','a','r','k'), 1},
155 { MS_MAKE_TAG('m','k','m','k'), 1},
158 static OPENTYPE_FEATURE_RECORD arabic_features[] =
160 { MS_MAKE_TAG('r','l','i','g'), 1},
161 { MS_MAKE_TAG('c','a','l','t'), 1},
162 { MS_MAKE_TAG('l','i','g','a'), 1},
163 { MS_MAKE_TAG('d','l','i','g'), 1},
164 { MS_MAKE_TAG('c','s','w','h'), 1},
165 { MS_MAKE_TAG('m','s','e','t'), 1},
168 static const char* required_arabic_features[] =
170 "fina",
171 "init",
172 "medi",
173 "rlig",
174 NULL
177 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
179 { MS_MAKE_TAG('c','u','r','s'), 1},
180 { MS_MAKE_TAG('k','e','r','n'), 1},
181 { MS_MAKE_TAG('m','a','r','k'), 1},
182 { MS_MAKE_TAG('m','k','m','k'), 1},
185 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
187 { MS_MAKE_TAG('c','c','m','p'), 1},
188 { MS_MAKE_TAG('d','l','i','g'), 0},
191 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
193 { MS_MAKE_TAG('k','e','r','n'), 1},
194 { MS_MAKE_TAG('m','a','r','k'), 1},
197 static OPENTYPE_FEATURE_RECORD syriac_features[] =
199 { MS_MAKE_TAG('r','l','i','g'), 1},
200 { MS_MAKE_TAG('c','a','l','t'), 1},
201 { MS_MAKE_TAG('l','i','g','a'), 1},
202 { MS_MAKE_TAG('d','l','i','g'), 1},
205 static const char* required_syriac_features[] =
207 "fina",
208 "fin2",
209 "fin3",
210 "init",
211 "medi",
212 "med2",
213 "rlig",
214 NULL
217 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
219 { MS_MAKE_TAG('k','e','r','n'), 1},
220 { MS_MAKE_TAG('m','a','r','k'), 1},
221 { MS_MAKE_TAG('m','k','m','k'), 1},
224 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
226 /* Presentation forms */
227 { MS_MAKE_TAG('b','l','w','s'), 1},
228 { MS_MAKE_TAG('a','b','v','s'), 1},
229 { MS_MAKE_TAG('p','s','t','s'), 1},
232 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
234 { MS_MAKE_TAG('a','b','v','s'), 1},
235 { MS_MAKE_TAG('b','l','w','s'), 1},
238 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
240 { MS_MAKE_TAG('a','b','v','m'), 1},
241 { MS_MAKE_TAG('b','l','w','m'), 1},
244 static OPENTYPE_FEATURE_RECORD phags_features[] =
246 { MS_MAKE_TAG('a','b','v','s'), 1},
247 { MS_MAKE_TAG('b','l','w','s'), 1},
248 { MS_MAKE_TAG('c','a','l','t'), 1},
251 static OPENTYPE_FEATURE_RECORD thai_features[] =
253 { MS_MAKE_TAG('c','c','m','p'), 1},
256 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
258 { MS_MAKE_TAG('k','e','r','n'), 1},
259 { MS_MAKE_TAG('m','a','r','k'), 1},
260 { MS_MAKE_TAG('m','k','m','k'), 1},
263 static const char* required_lao_features[] =
265 "ccmp",
266 NULL
269 static const char* required_devanagari_features[] =
271 "nukt",
272 "akhn",
273 "rphf",
274 "blwf",
275 "half",
276 "vatu",
277 "pres",
278 "abvs",
279 "blws",
280 "psts",
281 "haln",
282 NULL
285 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
287 { MS_MAKE_TAG('p','r','e','s'), 1},
288 { MS_MAKE_TAG('a','b','v','s'), 1},
289 { MS_MAKE_TAG('b','l','w','s'), 1},
290 { MS_MAKE_TAG('p','s','t','s'), 1},
291 { MS_MAKE_TAG('h','a','l','n'), 1},
292 { MS_MAKE_TAG('c','a','l','t'), 1},
295 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
297 { MS_MAKE_TAG('k','e','r','n'), 1},
298 { MS_MAKE_TAG('d','i','s','t'), 1},
299 { MS_MAKE_TAG('a','b','v','m'), 1},
300 { MS_MAKE_TAG('b','l','w','m'), 1},
303 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
305 { MS_MAKE_TAG('l','i','g','a'), 1},
306 { MS_MAKE_TAG('c','l','i','g'), 1},
309 static const char* required_bengali_features[] =
311 "nukt",
312 "akhn",
313 "rphf",
314 "blwf",
315 "half",
316 "vatu",
317 "pstf",
318 "init",
319 "abvs",
320 "blws",
321 "psts",
322 "haln",
323 NULL
326 static const char* required_gurmukhi_features[] =
328 "nukt",
329 "akhn",
330 "rphf",
331 "blwf",
332 "half",
333 "pstf",
334 "vatu",
335 "cjct",
336 "pres",
337 "abvs",
338 "blws",
339 "psts",
340 "haln",
341 "calt",
342 NULL
345 static const char* required_oriya_features[] =
347 "nukt",
348 "akhn",
349 "rphf",
350 "blwf",
351 "pstf",
352 "cjct",
353 "pres",
354 "abvs",
355 "blws",
356 "psts",
357 "haln",
358 "calt",
359 NULL
362 static const char* required_tamil_features[] =
364 "nukt",
365 "akhn",
366 "rphf",
367 "pref",
368 "half",
369 "pres",
370 "abvs",
371 "blws",
372 "psts",
373 "haln",
374 "calt",
375 NULL
378 static const char* required_telugu_features[] =
380 "nukt",
381 "akhn",
382 "rphf",
383 "pref",
384 "half",
385 "pstf",
386 "cjct",
387 "pres",
388 "abvs",
389 "blws",
390 "psts",
391 "haln",
392 "calt",
393 NULL
396 static OPENTYPE_FEATURE_RECORD khmer_features[] =
398 { MS_MAKE_TAG('p','r','e','s'), 1},
399 { MS_MAKE_TAG('b','l','w','s'), 1},
400 { MS_MAKE_TAG('a','b','v','s'), 1},
401 { MS_MAKE_TAG('p','s','t','s'), 1},
402 { MS_MAKE_TAG('c','l','i','g'), 1},
405 static const char* required_khmer_features[] =
407 "pref",
408 "blwf",
409 "abvf",
410 "pstf",
411 "pres",
412 "blws",
413 "abvs",
414 "psts",
415 "clig",
416 NULL
419 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
421 { MS_MAKE_TAG('d','i','s','t'), 1},
422 { MS_MAKE_TAG('b','l','w','m'), 1},
423 { MS_MAKE_TAG('a','b','v','m'), 1},
424 { MS_MAKE_TAG('m','k','m','k'), 1},
427 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
429 { MS_MAKE_TAG('c','c','m','p'), 1},
430 { MS_MAKE_TAG('l','o','c','l'), 1},
431 { MS_MAKE_TAG('c','a','l','t'), 1},
432 { MS_MAKE_TAG('l','i','g','a'), 1},
435 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
437 { MS_MAKE_TAG('c','c','m','p'), 1},
438 { MS_MAKE_TAG('l','o','c','l'), 1},
439 { MS_MAKE_TAG('c','a','l','t'), 1},
440 { MS_MAKE_TAG('r','l','i','g'), 1},
443 typedef struct ScriptShapeDataTag {
444 TEXTRANGE_PROPERTIES defaultTextRange;
445 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
446 const char** requiredFeatures;
447 OPENTYPE_TAG newOtTag;
448 ContextualShapingProc contextProc;
449 ShapeCharGlyphPropProc charGlyphPropProc;
450 } ScriptShapeData;
452 /* in order of scripts */
453 static const ScriptShapeData ShapingData[] =
455 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
456 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
457 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
458 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
459 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
460 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
461 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
462 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
463 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
464 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
465 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
466 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
467 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
468 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
469 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
470 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
471 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
472 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
473 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
474 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
475 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
476 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
477 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
478 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
479 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
480 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
481 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
482 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
483 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
497 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
498 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
499 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
500 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
501 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
502 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
503 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
504 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
505 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
506 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
508 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
509 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
511 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
512 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
513 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
516 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
518 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
519 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
522 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
523 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
524 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
526 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
527 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
528 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
529 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
530 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
531 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
532 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
533 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
534 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
535 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
536 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
539 extern scriptData scriptInformation[];
541 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
543 int i;
544 int out_index = GSUB_E_NOGLYPH;
546 TRACE("%i lookups\n", feature->lookup_count);
547 for (i = 0; i < feature->lookup_count; i++)
549 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
550 if (out_index != GSUB_E_NOGLYPH)
551 break;
553 if (out_index == GSUB_E_NOGLYPH)
554 TRACE("lookups found no glyphs\n");
555 else
557 int out2;
558 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
559 if (out2!=GSUB_E_NOGLYPH)
560 out_index = out2;
562 return out_index;
565 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
567 UINT charset;
569 if (psc->userScript != 0)
571 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
572 return ShapingData[psa->eScript].newOtTag;
573 else
574 return psc->userScript;
577 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
578 return ShapingData[psa->eScript].newOtTag;
580 if (scriptInformation[psa->eScript].scriptTag)
581 return scriptInformation[psa->eScript].scriptTag;
584 * fall back to the font charset
586 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
587 switch (charset)
589 case ANSI_CHARSET:
590 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
591 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
592 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
593 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
594 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
595 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
596 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
597 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
598 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
599 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
600 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
601 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
602 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
603 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
604 default: return MS_MAKE_TAG('l','a','t','n');
608 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
610 LoadedFeature *feature = NULL;
612 if (psc->GSUB_Table || psc->GPOS_Table)
614 int attempt = 2;
615 OPENTYPE_TAG tags;
616 OPENTYPE_TAG language;
617 OPENTYPE_TAG script = 0x00000000;
618 int cTags;
622 script = get_opentype_script(hdc,psa,psc,(attempt==2));
623 if (psc->userLang != 0)
624 language = psc->userLang;
625 else
626 language = MS_MAKE_TAG('d','f','l','t');
627 attempt--;
629 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
631 } while(attempt && !feature);
633 /* try in the default (latin) table */
634 if (!feature && !script)
635 OpenType_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
638 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
639 return feature;
642 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)
644 LoadedFeature *feature;
646 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
647 if (!feature)
648 return GSUB_E_NOFEATURE;
650 TRACE("applying feature %s\n",feat);
651 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
654 static VOID *load_gsub_table(HDC hdc)
656 VOID* GSUB_Table = NULL;
657 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
658 if (length != GDI_ERROR)
660 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
661 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
662 TRACE("Loaded GSUB table of %i bytes\n",length);
664 return GSUB_Table;
667 static VOID *load_gpos_table(HDC hdc)
669 VOID* GPOS_Table = NULL;
670 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
671 if (length != GDI_ERROR)
673 GPOS_Table = HeapAlloc(GetProcessHeap(),0,length);
674 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
675 TRACE("Loaded GPOS table of %i bytes\n",length);
677 return GPOS_Table;
680 static VOID *load_gdef_table(HDC hdc)
682 VOID* GDEF_Table = NULL;
683 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
684 if (length != GDI_ERROR)
686 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
687 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
688 TRACE("Loaded GDEF table of %i bytes\n",length);
690 return GDEF_Table;
693 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
695 if (!psc->GSUB_Table)
696 psc->GSUB_Table = load_gsub_table(hdc);
697 if (!psc->GPOS_Table)
698 psc->GPOS_Table = load_gpos_table(hdc);
699 if (!psc->GDEF_Table)
700 psc->GDEF_Table = load_gdef_table(hdc);
703 INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature)
705 WORD *glyphs;
706 INT glyph_count = count;
707 INT rc;
709 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
710 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
711 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
712 if (rc > GSUB_E_NOGLYPH)
713 rc = count - glyph_count;
714 else
715 rc = 0;
717 HeapFree(GetProcessHeap(),0,glyphs);
718 return rc;
721 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
723 int i;
725 for (i = 0; i < cGlyphs; i++)
727 if (!pGlyphProp[i].sva.fClusterStart)
729 int j;
730 for (j = 0; j < cChars; j++)
732 if (pwLogClust[j] == i)
734 int k = j;
735 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
736 k-=1;
737 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
738 pwLogClust[j] = pwLogClust[k];
745 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
747 if (changeCount == 0)
748 return;
749 else
751 int i;
752 int target_glyph = nextIndex - write_dir;
753 int seeking_glyph;
754 int target_index = -1;
755 int replacing_glyph = -1;
756 int changed = 0;
757 int top_logclust = 0;
759 if (changeCount > 0)
761 if (write_dir > 0)
762 target_glyph = nextIndex - changeCount;
763 else
764 target_glyph = nextIndex + (changeCount + 1);
767 seeking_glyph = target_glyph;
768 for (i = 0; i < chars; i++)
769 if (pwLogClust[i] > top_logclust)
770 top_logclust = pwLogClust[i];
772 do {
773 if (write_dir > 0)
774 for (i = 0; i < chars; i++)
776 if (pwLogClust[i] == seeking_glyph)
778 target_index = i;
779 break;
782 else
783 for (i = chars - 1; i >= 0; i--)
785 if (pwLogClust[i] == seeking_glyph)
787 target_index = i;
788 break;
791 if (target_index == -1)
792 seeking_glyph ++;
794 while (target_index == -1 && seeking_glyph <= top_logclust);
796 if (target_index == -1)
798 ERR("Unable to find target glyph\n");
799 return;
802 if (changeCount < 0)
804 /* merge glyphs */
805 for(i = target_index; i < chars && i >= 0; i+=write_dir)
807 if (pwLogClust[i] == target_glyph)
808 continue;
809 if(pwLogClust[i] == replacing_glyph)
810 pwLogClust[i] = target_glyph;
811 else
813 changed--;
814 if (changed >= changeCount)
816 replacing_glyph = pwLogClust[i];
817 pwLogClust[i] = target_glyph;
819 else
820 break;
824 /* renumber trailing indexes*/
825 for(i = target_index; i < chars && i >= 0; i+=write_dir)
827 if (pwLogClust[i] != target_glyph)
828 pwLogClust[i] += changeCount;
831 else
833 for(i = target_index; i < chars && i >= 0; i+=write_dir)
834 pwLogClust[i] += changeCount;
839 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 )
841 if (psc->GSUB_Table)
843 LoadedFeature *feature;
844 int lookup_index;
846 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
847 if (!feature)
848 return GSUB_E_NOFEATURE;
850 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
851 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
853 int i;
855 if (write_dir > 0)
856 i = 0;
857 else
858 i = *pcGlyphs-1;
859 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
860 while(i < *pcGlyphs && i >= 0)
862 INT nextIndex;
863 INT prevCount = *pcGlyphs;
865 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
866 if (*pcGlyphs != prevCount)
868 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
869 i = nextIndex;
871 else
872 i+=write_dir;
875 return *pcGlyphs;
877 return GSUB_E_NOFEATURE;
880 static VOID GPOS_apply_feature(ScriptCache *psc, LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, const SCRIPT_ANALYSIS *analysis, INT* piAdvance, LoadedFeature *feature, const WORD *glyphs, INT glyph_count, GOFFSET *pGoffset)
882 int i;
884 TRACE("%i lookups\n", feature->lookup_count);
885 for (i = 0; i < feature->lookup_count; i++)
887 int j;
888 for (j = 0; j < glyph_count; )
889 j = OpenType_apply_GPOS_lookup(psc, lpotm, lplogfont, analysis, piAdvance, feature->lookups[i], glyphs, j, glyph_count, pGoffset);
893 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
895 OPENTYPE_TAG tag;
896 HRESULT hr;
897 int count = 0;
899 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
901 return(SUCCEEDED(hr));
904 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
906 int i;
907 for (i = *pcGlyphs; i>=index; i--)
908 pwGlyphs[i+1] = pwGlyphs[i];
909 pwGlyphs[index] = glyph;
910 *pcGlyphs = *pcGlyphs+1;
911 if (write_dir < 0)
912 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
913 else
914 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
917 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)
919 CHAR *context_type;
920 int i,g;
921 WCHAR invalid = 0x25cc;
922 WORD invalid_glyph;
924 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
926 /* Mark invalid combinations */
927 for (i = 0; i < cChars; i++)
928 context_type[i] = lex(pwcChars[i]);
930 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
931 for (i = 1, g=1; i < cChars; i++, g++)
933 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
935 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
936 g++;
940 HeapFree(GetProcessHeap(),0,context_type);
943 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
945 if (i + delta < 0)
946 return 0;
947 if ( i+ delta >= cchLen)
948 return 0;
950 i += delta;
952 return chars[i];
955 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
957 if (i + delta < 0)
959 if (psa->fLinkBefore)
960 return jtR;
961 else
962 return jtU;
964 if ( i+ delta >= cchLen)
966 if (psa->fLinkAfter)
967 return jtL;
968 else
969 return jtU;
972 i += delta;
974 if (context_type[i] == jtT)
975 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
976 else
977 return context_type[i];
980 static inline BOOL right_join_causing(CHAR joining_type)
982 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
985 static inline BOOL left_join_causing(CHAR joining_type)
987 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
990 static inline BOOL word_break_causing(WCHAR chr)
992 /* we are working within a string of characters already guareented to
993 be within one script, Syriac, so we do not worry about any character
994 other than the space character outside of that range */
995 return (chr == 0 || chr == 0x20 );
998 static int combining_lexical_Arabic(WCHAR c)
1000 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1002 switch(c)
1004 case 0x064B:
1005 case 0x064C:
1006 case 0x064E:
1007 case 0x064F:
1008 case 0x0652:
1009 case 0x0657:
1010 case 0x0658:
1011 case 0x06E1: return Arab_DIAC1;
1012 case 0x064D:
1013 case 0x0650:
1014 case 0x0656: return Arab_DIAC2;
1015 case 0x0651: return Arab_DIAC3;
1016 case 0x0610:
1017 case 0x0611:
1018 case 0x0612:
1019 case 0x0613:
1020 case 0x0614:
1021 case 0x0659:
1022 case 0x06D6:
1023 case 0x06DC:
1024 case 0x06DF:
1025 case 0x06E0:
1026 case 0x06E2:
1027 case 0x06E4:
1028 case 0x06E7:
1029 case 0x06E8:
1030 case 0x06EB:
1031 case 0x06EC: return Arab_DIAC4;
1032 case 0x06E3:
1033 case 0x06EA:
1034 case 0x06ED: return Arab_DIAC5;
1035 case 0x0670: return Arab_DIAC6;
1036 case 0x0653: return Arab_DIAC7;
1037 case 0x0655:
1038 case 0x0654: return Arab_DIAC8;
1039 default: return Arab_Norm;
1044 * ContextualShape_Arabic
1046 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1048 CHAR *context_type;
1049 INT *context_shape;
1050 INT dirR, dirL;
1051 int i;
1053 if (*pcGlyphs != cChars)
1055 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1056 return;
1059 if (!psa->fLogicalOrder && psa->fRTL)
1061 dirR = 1;
1062 dirL = -1;
1064 else
1066 dirR = -1;
1067 dirL = 1;
1070 load_ot_tables(hdc, psc);
1072 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1073 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1075 for (i = 0; i < cChars; i++)
1076 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1078 for (i = 0; i < cChars; i++)
1080 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1081 context_shape[i] = Xr;
1082 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1083 context_shape[i] = Xl;
1084 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)))
1085 context_shape[i] = Xm;
1086 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1087 context_shape[i] = Xr;
1088 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1089 context_shape[i] = Xl;
1090 else
1091 context_shape[i] = Xn;
1094 /* Contextual Shaping */
1095 i = 0;
1096 while(i < *pcGlyphs)
1098 BOOL shaped = FALSE;
1100 if (psc->GSUB_Table)
1102 INT nextIndex;
1103 INT prevCount = *pcGlyphs;
1104 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1105 if (nextIndex > GSUB_E_NOGLYPH)
1107 i = nextIndex;
1108 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1110 shaped = (nextIndex > GSUB_E_NOGLYPH);
1113 if (!shaped)
1115 if (context_shape[i] == Xn)
1117 WORD newGlyph = pwOutGlyphs[i];
1118 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1120 /* fall back to presentation form B */
1121 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1122 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1123 pwOutGlyphs[i] = newGlyph;
1126 i++;
1130 HeapFree(GetProcessHeap(),0,context_shape);
1131 HeapFree(GetProcessHeap(),0,context_type);
1133 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1136 static int combining_lexical_Hebrew(WCHAR c)
1138 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};
1140 switch(c)
1142 case 0x05B0:
1143 case 0x05B1:
1144 case 0x05B2:
1145 case 0x05B3:
1146 case 0x05B4:
1147 case 0x05B5:
1148 case 0x05B6:
1149 case 0x05BB: return Hebr_DIAC;
1150 case 0x0599:
1151 case 0x05A1:
1152 case 0x05A9:
1153 case 0x05AE: return Hebr_CANT1;
1154 case 0x0597:
1155 case 0x05A8:
1156 case 0x05AC: return Hebr_CANT2;
1157 case 0x0592:
1158 case 0x0593:
1159 case 0x0594:
1160 case 0x0595:
1161 case 0x05A7:
1162 case 0x05AB: return Hebr_CANT3;
1163 case 0x0598:
1164 case 0x059C:
1165 case 0x059E:
1166 case 0x059F: return Hebr_CANT4;
1167 case 0x059D:
1168 case 0x05A0: return Hebr_CANT5;
1169 case 0x059B:
1170 case 0x05A5: return Hebr_CANT6;
1171 case 0x0591:
1172 case 0x05A3:
1173 case 0x05A6: return Hebr_CANT7;
1174 case 0x0596:
1175 case 0x05A4:
1176 case 0x05AA: return Hebr_CANT8;
1177 case 0x059A:
1178 case 0x05AD: return Hebr_CANT9;
1179 case 0x05AF: return Hebr_CANT10;
1180 case 0x05BC: return Hebr_DAGESH;
1181 case 0x05C4: return Hebr_DOTABV;
1182 case 0x05B9: return Hebr_HOLAM;
1183 case 0x05BD: return Hebr_METEG;
1184 case 0x05B7: return Hebr_PATAH;
1185 case 0x05B8: return Hebr_QAMATS;
1186 case 0x05BF: return Hebr_RAFE;
1187 case 0x05C1:
1188 case 0x05C2: return Hebr_SHINSIN;
1189 default: return Hebr_Norm;
1193 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1195 INT dirL;
1197 if (*pcGlyphs != cChars)
1199 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1200 return;
1203 if (!psa->fLogicalOrder && psa->fRTL)
1204 dirL = -1;
1205 else
1206 dirL = 1;
1208 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1212 * ContextualShape_Syriac
1215 static int combining_lexical_Syriac(WCHAR c)
1217 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};
1219 switch(c)
1221 case 0x730:
1222 case 0x733:
1223 case 0x736:
1224 case 0x73A:
1225 case 0x73D: return Syriac_DIAC1;
1226 case 0x731:
1227 case 0x734:
1228 case 0x737:
1229 case 0x73B:
1230 case 0x73E: return Syriac_DIAC2;
1231 case 0x740:
1232 case 0x749:
1233 case 0x74A: return Syriac_DIAC3;
1234 case 0x732:
1235 case 0x735:
1236 case 0x73F: return Syriac_DIAC4;
1237 case 0x738:
1238 case 0x739:
1239 case 0x73C: return Syriac_DIAC5;
1240 case 0x741:
1241 case 0x30A: return Syriac_DIAC6;
1242 case 0x742:
1243 case 0x325: return Syriac_DIAC7;
1244 case 0x747:
1245 case 0x303: return Syriac_DIAC8;
1246 case 0x748:
1247 case 0x32D:
1248 case 0x32E:
1249 case 0x330:
1250 case 0x331: return Syriac_DIAC9;
1251 case 0x308: return Syriac_DIAC10;
1252 case 0x304: return Syriac_DIAC11;
1253 case 0x307: return Syriac_DIAC12;
1254 case 0x323: return Syriac_DIAC13;
1255 case 0x743: return Syriac_DIAC14;
1256 case 0x744: return Syriac_DIAC15;
1257 case 0x745: return Syriac_DIAC16;
1258 case 0x746: return Syriac_DIAC17;
1259 default: return Syriac_Norm;
1263 #define ALAPH 0x710
1264 #define DALATH 0x715
1265 #define RISH 0x72A
1267 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1269 CHAR *context_type;
1270 INT *context_shape;
1271 INT dirR, dirL;
1272 int i;
1274 if (*pcGlyphs != cChars)
1276 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1277 return;
1280 if (!psa->fLogicalOrder && psa->fRTL)
1282 dirR = 1;
1283 dirL = -1;
1285 else
1287 dirR = -1;
1288 dirL = 1;
1291 load_ot_tables(hdc, psc);
1293 if (!psc->GSUB_Table)
1294 return;
1296 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1297 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1299 for (i = 0; i < cChars; i++)
1300 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1302 for (i = 0; i < cChars; i++)
1304 if (pwcChars[i] == ALAPH)
1306 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1308 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1309 context_shape[i] = Afj;
1310 else if ( rchar != DALATH && rchar != RISH &&
1311 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1312 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1313 context_shape[i] = Afn;
1314 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1315 context_shape[i] = Afx;
1316 else
1317 context_shape[i] = Xn;
1319 else if (context_type[i] == jtR &&
1320 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1321 context_shape[i] = Xr;
1322 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1323 context_shape[i] = Xl;
1324 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)))
1325 context_shape[i] = Xm;
1326 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1327 context_shape[i] = Xr;
1328 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1329 context_shape[i] = Xl;
1330 else
1331 context_shape[i] = Xn;
1334 /* Contextual Shaping */
1335 i = 0;
1336 while(i < *pcGlyphs)
1338 INT nextIndex;
1339 INT prevCount = *pcGlyphs;
1340 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1341 if (nextIndex > GSUB_E_NOGLYPH)
1343 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1344 i = nextIndex;
1346 else
1347 i++;
1350 HeapFree(GetProcessHeap(),0,context_shape);
1351 HeapFree(GetProcessHeap(),0,context_type);
1353 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1356 static int combining_lexical_Thaana(WCHAR c)
1358 enum {Thaana_Norm=0, Thaana_FILI};
1360 switch(c)
1362 case 0x7A6:
1363 case 0x7A7:
1364 case 0x7A8:
1365 case 0x7A9:
1366 case 0x7AA:
1367 case 0x7AB:
1368 case 0x7AC:
1369 case 0x7AD:
1370 case 0x7AE:
1371 case 0x7AF: return Thaana_FILI;
1372 default: return Thaana_Norm;
1376 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1378 INT dirL;
1380 if (*pcGlyphs != cChars)
1382 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1383 return;
1386 if (!psa->fLogicalOrder && psa->fRTL)
1387 dirL = -1;
1388 else
1389 dirL = 1;
1391 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1395 * ContextualShape_Phags_pa
1398 #define phags_pa_CANDRABINDU 0xA873
1399 #define phags_pa_START 0xA840
1400 #define phags_pa_END 0xA87F
1402 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1404 INT *context_shape;
1405 INT dirR, dirL;
1406 int i;
1408 if (*pcGlyphs != cChars)
1410 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1411 return;
1414 if (!psa->fLogicalOrder && psa->fRTL)
1416 dirR = 1;
1417 dirL = -1;
1419 else
1421 dirR = -1;
1422 dirL = 1;
1425 load_ot_tables(hdc, psc);
1427 if (!psc->GSUB_Table)
1428 return;
1430 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1432 for (i = 0; i < cChars; i++)
1434 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1436 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1437 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1438 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1439 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1441 if (jrchar && jlchar)
1442 context_shape[i] = Xm;
1443 else if (jrchar)
1444 context_shape[i] = Xr;
1445 else if (jlchar)
1446 context_shape[i] = Xl;
1447 else
1448 context_shape[i] = Xn;
1450 else
1451 context_shape[i] = -1;
1454 /* Contextual Shaping */
1455 i = 0;
1456 while(i < *pcGlyphs)
1458 if (context_shape[i] >= 0)
1460 INT nextIndex;
1461 INT prevCount = *pcGlyphs;
1462 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1463 if (nextIndex > GSUB_E_NOGLYPH)
1465 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1466 i = nextIndex;
1468 else
1469 i++;
1471 else
1472 i++;
1475 HeapFree(GetProcessHeap(),0,context_shape);
1478 static int combining_lexical_Thai(WCHAR c)
1480 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1482 switch(c)
1484 case 0xE31:
1485 case 0xE34:
1486 case 0xE35:
1487 case 0xE36:
1488 case 0xE37: return Thai_ABOVE1;
1489 case 0xE47:
1490 case 0xE4D: return Thai_ABOVE2;
1491 case 0xE48:
1492 case 0xE49:
1493 case 0xE4A:
1494 case 0xE4B: return Thai_ABOVE3;
1495 case 0xE4C:
1496 case 0xE4E: return Thai_ABOVE4;
1497 case 0xE38:
1498 case 0xE39: return Thai_BELOW1;
1499 case 0xE3A: return Thai_BELOW2;
1500 case 0xE33: return Thai_AM;
1501 default: return Thai_Norm;
1505 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1507 INT dirL;
1509 if (*pcGlyphs != cChars)
1511 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1512 return;
1515 if (!psa->fLogicalOrder && psa->fRTL)
1516 dirL = -1;
1517 else
1518 dirL = 1;
1520 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1523 static int combining_lexical_Lao(WCHAR c)
1525 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1527 switch(c)
1529 case 0xEB1:
1530 case 0xEB4:
1531 case 0xEB5:
1532 case 0xEB6:
1533 case 0xEB7:
1534 case 0xEBB:
1535 case 0xECD: return Lao_ABOVE1;
1536 case 0xEC8:
1537 case 0xEC9:
1538 case 0xECA:
1539 case 0xECB:
1540 case 0xECC: return Lao_ABOVE2;
1541 case 0xEBC: return Lao_BELOW1;
1542 case 0xEB8:
1543 case 0xEB9: return Lao_BELOW2;
1544 case 0xEB3: return Lao_AM;
1545 default: return Lao_Norm;
1549 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1551 INT dirL;
1553 if (*pcGlyphs != cChars)
1555 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1556 return;
1559 if (!psa->fLogicalOrder && psa->fRTL)
1560 dirL = -1;
1561 else
1562 dirL = 1;
1564 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1567 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1569 int i;
1571 /* Replace */
1572 pwOutChars[cWalk] = replacements[0];
1573 cWalk=cWalk+1;
1575 /* Insert */
1576 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1578 int j;
1579 for (j = *pcChars; j > cWalk; j--)
1580 pwOutChars[j] = pwOutChars[j-1];
1581 *pcChars= *pcChars+1;
1582 pwOutChars[cWalk] = replacements[i];
1583 cWalk = cWalk+1;
1587 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1589 int i;
1590 int cWalk;
1592 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1594 for (i = 0; vowels[i].base != 0x0; i++)
1596 if (pwOutChars[cWalk] == vowels[i].base)
1598 int o = 0;
1599 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1600 if (vowels[i].parts[1]) { cWalk++; o++; }
1601 if (vowels[i].parts[2]) { cWalk++; o++; }
1602 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1603 break;
1609 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1611 int i;
1612 int offset = 0;
1613 int cWalk;
1615 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1617 for (i = 0; consonants[i].output!= 0x0; i++)
1619 int j;
1620 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1621 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1622 break;
1624 if (consonants[i].parts[j]==0x0) /* matched all */
1626 int k;
1627 j--;
1628 pwOutChars[cWalk] = consonants[i].output;
1629 for(k = cWalk+1; k < *pcChars - j; k++)
1630 pwOutChars[k] = pwOutChars[k+j];
1631 *pcChars = *pcChars - j;
1632 for (k = j ; k > 0; k--)
1633 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1634 offset += j;
1635 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1636 pwLogClust[k]--;
1637 break;
1640 cWalk++;
1644 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1646 if (s->ralf >= 0)
1648 int j;
1649 WORD Ra = pwChar[s->start];
1650 WORD H = pwChar[s->start+1];
1652 TRACE("Doing reorder of Ra to %i\n",s->base);
1653 for (j = s->start; j < s->base-1; j++)
1654 pwChar[j] = pwChar[j+2];
1655 pwChar[s->base-1] = Ra;
1656 pwChar[s->base] = H;
1658 s->ralf = s->base-1;
1659 s->base -= 2;
1663 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1665 if (s->ralf >= 0)
1667 int j,loc;
1668 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1669 WORD Ra = pwChar[s->start];
1670 WORD H = pwChar[s->start+1];
1671 for (loc = s->end; loc > stop; loc--)
1672 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1673 break;
1675 TRACE("Doing reorder of Ra to %i\n",loc);
1676 for (j = s->start; j < loc-1; j++)
1677 pwChar[j] = pwChar[j+2];
1678 pwChar[loc-1] = Ra;
1679 pwChar[loc] = H;
1681 s->ralf = loc-1;
1682 s->base -= 2;
1683 if (s->blwf >= 0) s->blwf -= 2;
1684 if (s->pref >= 0) s->pref -= 2;
1688 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1690 if (s->ralf >= 0)
1692 int j;
1693 WORD Ra = pwChar[s->start];
1694 WORD H = pwChar[s->start+1];
1696 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1697 for (j = s->start; j < s->end-1; j++)
1698 pwChar[j] = pwChar[j+2];
1699 pwChar[s->end-1] = Ra;
1700 pwChar[s->end] = H;
1702 s->ralf = s->end-1;
1703 s->base -= 2;
1704 if (s->blwf >= 0) s->blwf -= 2;
1705 if (s->pref >= 0) s->pref -= 2;
1709 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1711 int i;
1713 /* reorder Matras */
1714 if (s->end > s->base)
1716 for (i = 1; i <= s->end-s->base; i++)
1718 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1720 int j;
1721 WCHAR c = pwChar[s->base+i];
1722 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1723 for (j = s->base+i; j > s->base; j--)
1724 pwChar[j] = pwChar[j-1];
1725 pwChar[s->base] = c;
1727 if (s->ralf >= s->base) s->ralf++;
1728 if (s->blwf >= s->base) s->blwf++;
1729 if (s->pref >= s->base) s->pref++;
1730 s->base ++;
1736 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1738 int i;
1740 /* reorder Matras */
1741 if (s->end > s->base)
1743 for (i = 1; i <= s->end-s->base; i++)
1745 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1747 int j;
1748 WCHAR c = pwChar[s->base+i];
1749 TRACE("Doing reorder of %x to %i\n",c,s->start);
1750 for (j = s->base+i; j > s->start; j--)
1751 pwChar[j] = pwChar[j-1];
1752 pwChar[s->start] = c;
1754 if (s->ralf >= 0) s->ralf++;
1755 if (s->blwf >= 0) s->blwf++;
1756 if (s->pref >= 0) s->pref++;
1757 s->base ++;
1763 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1765 if (s->blwf >= 0 && g->blwf > g->base)
1767 int j,loc;
1768 int g_offset;
1769 for (loc = s->end; loc > s->blwf; loc--)
1770 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1771 break;
1773 g_offset = (loc - s->blwf) - 1;
1775 if (loc != s->blwf)
1777 WORD blwf = glyphs[g->blwf];
1778 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1779 /* do not care about the pwChar array anymore, just the glyphs */
1780 for (j = 0; j < g_offset; j++)
1781 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1782 glyphs[g->blwf + g_offset] = blwf;
1787 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1789 int i;
1791 /* reorder previously moved Matras to correct position*/
1792 for (i = s->start; i < s->base; i++)
1794 if (lexical(pwChar[i]) == lex_Matra_pre)
1796 int j;
1797 int g_start = g->start + i - s->start;
1798 if (g_start < g->base -1 )
1800 WCHAR og = glyphs[g_start];
1801 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1802 for (j = g_start; j < g->base-1; j++)
1803 glyphs[j] = glyphs[j+1];
1804 glyphs[g->base-1] = og;
1810 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1812 if (s->pref >= 0 && g->pref > g->base)
1814 int j;
1815 WCHAR og = glyphs[g->pref];
1816 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1817 for (j = g->pref; j > g->base; j--)
1818 glyphs[j] = glyphs[j-1];
1819 glyphs[g->base] = og;
1823 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1825 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1826 if (s->start == s->base && s->base == s->end) return;
1827 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1829 Reorder_Ra_follows_base(pwChar, s, lexical);
1830 Reorder_Matra_precede_base(pwChar, s, lexical);
1833 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1835 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1836 if (s->start == s->base && s->base == s->end) return;
1837 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1839 Reorder_Ra_follows_matra(pwChar, s, lexical);
1840 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1843 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1845 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1846 if (s->start == s->base && s->base == s->end) return;
1847 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1849 Reorder_Ra_follows_base(pwChar, s, lexical);
1850 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1853 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1855 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1856 if (s->start == s->base && s->base == s->end) return;
1857 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1859 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1860 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1863 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1865 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1866 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1867 if (s->start == s->base && s->base == s->end) return;
1868 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1870 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1873 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1875 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1876 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1877 if (s->start == s->base && s->base == s->end) return;
1878 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1880 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1881 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1885 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1887 if (shift == 0)
1888 return;
1890 if (glyph_index->start > index)
1891 glyph_index->start += shift;
1892 if (glyph_index->base > index)
1893 glyph_index->base+= shift;
1894 if (glyph_index->end > index)
1895 glyph_index->end+= shift;
1896 if (glyph_index->ralf > index)
1897 glyph_index->ralf+= shift;
1898 if (glyph_index->blwf > index)
1899 glyph_index->blwf+= shift;
1900 if (glyph_index->pref > index)
1901 glyph_index->pref+= shift;
1904 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 )
1906 int index = glyph_index->start;
1908 if (!feature)
1909 return;
1911 while(index <= glyph_index->end)
1913 INT nextIndex;
1914 INT prevCount = *pcGlyphs;
1915 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1916 if (nextIndex > GSUB_E_NOGLYPH)
1918 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1919 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1920 index = nextIndex;
1922 else
1923 index++;
1927 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1929 int i = 0;
1930 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)))))
1931 i++;
1932 if (index + i <= end-1)
1933 return index + i;
1934 else
1935 return -1;
1938 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)
1940 INT index, nextIndex;
1941 INT count,g_offset;
1943 count = syllable->base - syllable->start;
1945 g_offset = 0;
1946 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1947 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1949 INT prevCount = *pcGlyphs;
1950 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1951 if (nextIndex > GSUB_E_NOGLYPH)
1953 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1954 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1955 g_offset += (*pcGlyphs - prevCount);
1958 index+=2;
1959 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1963 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)
1965 INT nextIndex;
1966 INT prevCount = *pcGlyphs;
1968 if (syllable->ralf >= 0)
1970 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1971 if (nextIndex > GSUB_E_NOGLYPH)
1973 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1974 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1979 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1981 int i = 0;
1982 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1983 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1984 is_consonant(lexical(pwChars[index+i+1])))))
1985 i++;
1986 if (index + i <= end-1)
1987 return index+i;
1988 else
1989 return -1;
1992 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)
1994 INT index, nextIndex;
1995 INT count, g_offset=0;
1996 INT ralf = syllable->ralf;
1998 count = syllable->end - syllable->base;
2000 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2002 while (index >= 0)
2004 INT prevCount = *pcGlyphs;
2005 if (ralf >=0 && ralf < index)
2007 g_offset--;
2008 ralf = -1;
2011 if (!modern)
2013 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2014 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2015 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2018 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2019 if (nextIndex > GSUB_E_NOGLYPH)
2021 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2022 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2023 g_offset += (*pcGlyphs - prevCount);
2025 else if (!modern)
2027 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2028 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2029 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2032 index+=2;
2033 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2037 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)
2039 int c;
2040 int overall_shift = 0;
2041 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2042 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2043 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2044 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2045 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2046 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2047 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2048 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2049 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2050 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2051 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2052 IndicSyllable glyph_indexs;
2054 for (c = 0; c < syllable_count; c++)
2056 int old_end;
2057 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2058 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2059 old_end = glyph_indexs.end;
2061 if (locl)
2063 TRACE("applying feature locl\n");
2064 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2066 if (nukt)
2068 TRACE("applying feature nukt\n");
2069 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2071 if (akhn)
2073 TRACE("applying feature akhn\n");
2074 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2077 if (rphf)
2078 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2079 if (rkrf)
2081 TRACE("applying feature rkrf\n");
2082 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2084 if (pref)
2085 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2086 if (blwf)
2088 if (!modern)
2089 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2091 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2094 if (half)
2095 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2096 if (pstf)
2098 TRACE("applying feature pstf\n");
2099 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2101 if (vatu)
2103 TRACE("applying feature vatu\n");
2104 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2106 if (cjct)
2108 TRACE("applying feature cjct\n");
2109 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2112 if (second_reorder)
2113 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2115 overall_shift += glyph_indexs.end - old_end;
2119 static inline int unicode_lex(WCHAR c)
2121 int type;
2123 if (!c) return lex_Generic;
2124 if (c == 0x200D) return lex_ZWJ;
2125 if (c == 0x200C) return lex_ZWNJ;
2126 if (c == 0x00A0) return lex_NBSP;
2128 type = get_table_entry( indic_syllabic_table, c );
2130 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2132 switch( type )
2134 case 0x0d07: /* Unknown */
2135 case 0x0e07: /* Unknwon */
2136 default: return lex_Generic;
2137 case 0x0001:
2138 case 0x0002:
2139 case 0x0011:
2140 case 0x0012:
2141 case 0x0013:
2142 case 0x0014: return lex_Modifier;
2143 case 0x0003:
2144 case 0x0009:
2145 case 0x000a:
2146 case 0x000b:
2147 case 0x000d:
2148 case 0x000e:
2149 case 0x000f:
2150 case 0x0010: return lex_Consonant;
2151 case 0x0004: return lex_Nukta;
2152 case 0x0005: return lex_Halant;
2153 case 0x0006:
2154 case 0x0008: return lex_Vowel;
2155 case 0x0007:
2156 case 0x0107: return lex_Matra_post;
2157 case 0x0207:
2158 case 0x0307: return lex_Matra_pre;
2159 case 0x0807:
2160 case 0x0907:
2161 case 0x0a07:
2162 case 0x0b07:
2163 case 0x0c07:
2164 case 0x0407: return lex_Composed_Vowel;
2165 case 0x0507: return lex_Matra_above;
2166 case 0x0607: return lex_Matra_below;
2167 case 0x000c: return lex_Ra;
2171 static int sinhala_lex(WCHAR c)
2173 switch (c)
2175 case 0x0DDA:
2176 case 0x0DDD:
2177 case 0x0DDC:
2178 case 0x0DDE: return lex_Matra_post;
2179 default:
2180 return unicode_lex(c);
2184 static const VowelComponents Sinhala_vowels[] = {
2185 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2186 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2187 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2188 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2189 {0x0000, {0x0000,0x0000,0x0}}};
2191 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2193 int cCount = cChars;
2194 int i;
2195 WCHAR *input;
2196 IndicSyllable *syllables = NULL;
2197 int syllable_count = 0;
2199 if (*pcGlyphs != cChars)
2201 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2202 return;
2205 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2207 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2209 /* Step 1: Decompose multi part vowels */
2210 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2212 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2214 /* Step 2: Reorder within Syllables */
2215 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2216 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2218 /* Step 3: Strip dangling joiners */
2219 for (i = 0; i < cCount; i++)
2221 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2222 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2223 input[i] = 0x0020;
2226 /* Step 4: Base Form application to syllables */
2227 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2228 *pcGlyphs = cCount;
2229 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2231 HeapFree(GetProcessHeap(),0,input);
2232 HeapFree(GetProcessHeap(),0,syllables);
2235 static int devanagari_lex(WCHAR c)
2237 switch (c)
2239 case 0x0930: return lex_Ra;
2240 default:
2241 return unicode_lex(c);
2245 static const ConsonantComponents Devanagari_consonants[] ={
2246 {{0x0928, 0x093C, 0x00000}, 0x0929},
2247 {{0x0930, 0x093C, 0x00000}, 0x0931},
2248 {{0x0933, 0x093C, 0x00000}, 0x0934},
2249 {{0x0915, 0x093C, 0x00000}, 0x0958},
2250 {{0x0916, 0x093C, 0x00000}, 0x0959},
2251 {{0x0917, 0x093C, 0x00000}, 0x095A},
2252 {{0x091C, 0x093C, 0x00000}, 0x095B},
2253 {{0x0921, 0x093C, 0x00000}, 0x095C},
2254 {{0x0922, 0x093C, 0x00000}, 0x095D},
2255 {{0x092B, 0x093C, 0x00000}, 0x095E},
2256 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2258 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2260 int cCount = cChars;
2261 WCHAR *input;
2262 IndicSyllable *syllables = NULL;
2263 int syllable_count = 0;
2264 BOOL modern = get_GSUB_Indic2(psa, psc);
2266 if (*pcGlyphs != cChars)
2268 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2269 return;
2272 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2273 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2275 /* Step 1: Compose Consonant and Nukta */
2276 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2277 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2279 /* Step 2: Reorder within Syllables */
2280 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2281 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2282 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2283 *pcGlyphs = cCount;
2285 /* Step 3: Base Form application to syllables */
2286 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2288 HeapFree(GetProcessHeap(),0,input);
2289 HeapFree(GetProcessHeap(),0,syllables);
2292 static int bengali_lex(WCHAR c)
2294 switch (c)
2296 case 0x09B0: return lex_Ra;
2297 default:
2298 return unicode_lex(c);
2302 static const VowelComponents Bengali_vowels[] = {
2303 {0x09CB, {0x09C7,0x09BE,0x0000}},
2304 {0x09CC, {0x09C7,0x09D7,0x0000}},
2305 {0x0000, {0x0000,0x0000,0x0000}}};
2307 static const ConsonantComponents Bengali_consonants[] = {
2308 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2309 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2310 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2311 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2312 {{0x0000,0x0000,0x0000}, 0x0000}};
2314 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2316 int cCount = cChars;
2317 WCHAR *input;
2318 IndicSyllable *syllables = NULL;
2319 int syllable_count = 0;
2320 BOOL modern = get_GSUB_Indic2(psa, psc);
2322 if (*pcGlyphs != cChars)
2324 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2325 return;
2328 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2329 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2331 /* Step 1: Decompose Vowels and Compose Consonants */
2332 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2333 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2334 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2336 /* Step 2: Reorder within Syllables */
2337 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2338 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2339 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2340 *pcGlyphs = cCount;
2342 /* Step 3: Initial form is only applied to the beginning of words */
2343 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2345 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2347 int index = cCount;
2348 int gCount = 1;
2349 if (index > 0) index++;
2351 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2355 /* Step 4: Base Form application to syllables */
2356 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2358 HeapFree(GetProcessHeap(),0,input);
2359 HeapFree(GetProcessHeap(),0,syllables);
2362 static int gurmukhi_lex(WCHAR c)
2364 if (c == 0x0A71)
2365 return lex_Modifier;
2366 else
2367 return unicode_lex(c);
2370 static const ConsonantComponents Gurmukhi_consonants[] = {
2371 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2372 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2373 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2374 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2375 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2376 {{0x0000,0x0000,0x0000}, 0x0000}};
2378 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2380 int cCount = cChars;
2381 WCHAR *input;
2382 IndicSyllable *syllables = NULL;
2383 int syllable_count = 0;
2384 BOOL modern = get_GSUB_Indic2(psa, psc);
2386 if (*pcGlyphs != cChars)
2388 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2389 return;
2392 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2393 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2395 /* Step 1: Compose Consonants */
2396 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2397 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2399 /* Step 2: Reorder within Syllables */
2400 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2401 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2402 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2403 *pcGlyphs = cCount;
2405 /* Step 3: Base Form application to syllables */
2406 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2408 HeapFree(GetProcessHeap(),0,input);
2409 HeapFree(GetProcessHeap(),0,syllables);
2412 static int gujarati_lex(WCHAR c)
2414 switch (c)
2416 case 0x0AB0: return lex_Ra;
2417 default:
2418 return unicode_lex(c);
2422 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2424 int cCount = cChars;
2425 WCHAR *input;
2426 IndicSyllable *syllables = NULL;
2427 int syllable_count = 0;
2428 BOOL modern = get_GSUB_Indic2(psa, psc);
2430 if (*pcGlyphs != cChars)
2432 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2433 return;
2436 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2437 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2439 /* Step 1: Reorder within Syllables */
2440 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2441 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2442 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2443 *pcGlyphs = cCount;
2445 /* Step 2: Base Form application to syllables */
2446 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2448 HeapFree(GetProcessHeap(),0,input);
2449 HeapFree(GetProcessHeap(),0,syllables);
2452 static int oriya_lex(WCHAR c)
2454 switch (c)
2456 case 0x0B30: return lex_Ra;
2457 default:
2458 return unicode_lex(c);
2462 static const VowelComponents Oriya_vowels[] = {
2463 {0x0B48, {0x0B47,0x0B56,0x0000}},
2464 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2465 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2466 {0x0000, {0x0000,0x0000,0x0000}}};
2468 static const ConsonantComponents Oriya_consonants[] = {
2469 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2470 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2471 {{0x0000,0x0000,0x0000}, 0x0000}};
2473 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2475 int cCount = cChars;
2476 WCHAR *input;
2477 IndicSyllable *syllables = NULL;
2478 int syllable_count = 0;
2479 BOOL modern = get_GSUB_Indic2(psa, psc);
2481 if (*pcGlyphs != cChars)
2483 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2484 return;
2487 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2488 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2490 /* Step 1: Decompose Vowels and Compose Consonants */
2491 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2492 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2493 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2495 /* Step 2: Reorder within Syllables */
2496 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2497 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2498 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2499 *pcGlyphs = cCount;
2501 /* Step 3: Base Form application to syllables */
2502 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2504 HeapFree(GetProcessHeap(),0,input);
2505 HeapFree(GetProcessHeap(),0,syllables);
2508 static int tamil_lex(WCHAR c)
2510 return unicode_lex(c);
2513 static const VowelComponents Tamil_vowels[] = {
2514 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2515 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2516 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2517 {0x0000, {0x0000,0x0000,0x0000}}};
2519 static const ConsonantComponents Tamil_consonants[] = {
2520 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2521 {{0x0000,0x0000,0x0000}, 0x0000}};
2523 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2525 int cCount = cChars;
2526 WCHAR *input;
2527 IndicSyllable *syllables = NULL;
2528 int syllable_count = 0;
2529 BOOL modern = get_GSUB_Indic2(psa, psc);
2531 if (*pcGlyphs != cChars)
2533 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2534 return;
2537 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2538 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2540 /* Step 1: Decompose Vowels and Compose Consonants */
2541 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2542 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2543 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2545 /* Step 2: Reorder within Syllables */
2546 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2547 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2548 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2549 *pcGlyphs = cCount;
2551 /* Step 3: Base Form application to syllables */
2552 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2554 HeapFree(GetProcessHeap(),0,input);
2555 HeapFree(GetProcessHeap(),0,syllables);
2558 static int telugu_lex(WCHAR c)
2560 switch (c)
2562 case 0x0C43:
2563 case 0x0C44: return lex_Modifier;
2564 default:
2565 return unicode_lex(c);
2569 static const VowelComponents Telugu_vowels[] = {
2570 {0x0C48, {0x0C46,0x0C56,0x0000}},
2571 {0x0000, {0x0000,0x0000,0x0000}}};
2573 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2575 int cCount = cChars;
2576 WCHAR *input;
2577 IndicSyllable *syllables = NULL;
2578 int syllable_count = 0;
2579 BOOL modern = get_GSUB_Indic2(psa, psc);
2581 if (*pcGlyphs != cChars)
2583 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2584 return;
2587 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2588 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2590 /* Step 1: Decompose Vowels */
2591 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2592 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2594 /* Step 2: Reorder within Syllables */
2595 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2596 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2597 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2598 *pcGlyphs = cCount;
2600 /* Step 3: Base Form application to syllables */
2601 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2603 HeapFree(GetProcessHeap(),0,input);
2604 HeapFree(GetProcessHeap(),0,syllables);
2607 static int kannada_lex(WCHAR c)
2609 switch (c)
2611 case 0x0CB0: return lex_Ra;
2612 default:
2613 return unicode_lex(c);
2617 static const VowelComponents Kannada_vowels[] = {
2618 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2619 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2620 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2621 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2622 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2623 {0x0000, {0x0000,0x0000,0x0000}}};
2625 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2627 int cCount = cChars;
2628 WCHAR *input;
2629 IndicSyllable *syllables = NULL;
2630 int syllable_count = 0;
2631 BOOL modern = get_GSUB_Indic2(psa, psc);
2633 if (*pcGlyphs != cChars)
2635 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2636 return;
2639 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2640 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2642 /* Step 1: Decompose Vowels */
2643 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2644 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2646 /* Step 2: Reorder within Syllables */
2647 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2648 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2649 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2650 *pcGlyphs = cCount;
2652 /* Step 3: Base Form application to syllables */
2653 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2655 HeapFree(GetProcessHeap(),0,input);
2656 HeapFree(GetProcessHeap(),0,syllables);
2659 static int malayalam_lex(WCHAR c)
2661 return unicode_lex(c);
2664 static const VowelComponents Malayalam_vowels[] = {
2665 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2666 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2667 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2668 {0x0000, {0x0000,0x0000,0x0000}}};
2670 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2672 int cCount = cChars;
2673 WCHAR *input;
2674 IndicSyllable *syllables = NULL;
2675 int syllable_count = 0;
2676 BOOL modern = get_GSUB_Indic2(psa, psc);
2678 if (*pcGlyphs != cChars)
2680 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2681 return;
2684 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2685 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2687 /* Step 1: Decompose Vowels */
2688 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2689 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2691 /* Step 2: Reorder within Syllables */
2692 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2693 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2694 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2695 *pcGlyphs = cCount;
2697 /* Step 3: Base Form application to syllables */
2698 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2700 HeapFree(GetProcessHeap(),0,input);
2701 HeapFree(GetProcessHeap(),0,syllables);
2704 static int khmer_lex(WCHAR c)
2706 return unicode_lex(c);
2709 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2711 int cCount = cChars;
2712 WCHAR *input;
2713 IndicSyllable *syllables = NULL;
2714 int syllable_count = 0;
2716 if (*pcGlyphs != cChars)
2718 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2719 return;
2722 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2723 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2725 /* Step 1: Reorder within Syllables */
2726 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2727 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2728 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2729 *pcGlyphs = cCount;
2731 /* Step 2: Base Form application to syllables */
2732 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2734 HeapFree(GetProcessHeap(),0,input);
2735 HeapFree(GetProcessHeap(),0,syllables);
2738 static inline BOOL mongolian_wordbreak(WCHAR chr)
2740 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2743 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2745 INT *context_shape;
2746 INT dirL;
2747 int i;
2749 if (*pcGlyphs != cChars)
2751 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2752 return;
2755 if (!psa->fLogicalOrder && psa->fRTL)
2756 dirL = -1;
2757 else
2758 dirL = 1;
2760 if (!psc->GSUB_Table)
2761 return;
2763 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2765 for (i = 0; i < cChars; i++)
2767 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2769 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2770 context_shape[i] = Xn;
2771 else
2772 context_shape[i] = Xl;
2774 else
2776 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2777 context_shape[i] = Xr;
2778 else
2779 context_shape[i] = Xm;
2783 /* Contextual Shaping */
2784 i = 0;
2785 while(i < *pcGlyphs)
2787 INT nextIndex;
2788 INT prevCount = *pcGlyphs;
2789 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2790 if (nextIndex > GSUB_E_NOGLYPH)
2792 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2793 i = nextIndex;
2795 else
2796 i++;
2799 HeapFree(GetProcessHeap(),0,context_shape);
2802 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)
2804 int i,k;
2806 for (i = 0; i < cGlyphs; i++)
2808 int char_index[20];
2809 int char_count = 0;
2811 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2812 if (k>=0)
2814 for (; k < cChars && pwLogClust[k] == i; k++)
2815 char_index[char_count++] = k;
2818 if (char_count == 0)
2819 continue;
2821 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2823 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2824 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2826 else
2827 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2830 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2831 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2834 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 )
2836 int i,k;
2837 int initGlyph, finaGlyph;
2838 INT dirR, dirL;
2839 BYTE *spaces;
2841 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2842 memset(spaces,0,cGlyphs);
2844 if (!psa->fLogicalOrder && psa->fRTL)
2846 initGlyph = cGlyphs-1;
2847 finaGlyph = 0;
2848 dirR = 1;
2849 dirL = -1;
2851 else
2853 initGlyph = 0;
2854 finaGlyph = cGlyphs-1;
2855 dirR = -1;
2856 dirL = 1;
2859 for (i = 0; i < cGlyphs; i++)
2861 for (k = 0; k < cChars; k++)
2862 if (pwLogClust[k] == i)
2864 if (pwcChars[k] == 0x0020)
2865 spaces[i] = 1;
2869 for (i = 0; i < cGlyphs; i++)
2871 int char_index[20];
2872 int char_count = 0;
2873 BOOL isInit, isFinal;
2875 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2876 if (k>=0)
2878 for (; k < cChars && pwLogClust[k] == i; k++)
2879 char_index[char_count++] = k;
2882 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2883 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2885 if (char_count == 0)
2886 continue;
2888 if (char_count == 1)
2890 if (pwcChars[char_index[0]] == 0x0020) /* space */
2892 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2893 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2895 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2896 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2897 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2899 if (!isInit && !isFinal)
2900 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2901 else if (isInit)
2902 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2903 else
2904 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2906 else if (!isInit)
2908 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2909 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2910 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2911 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2912 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2913 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2914 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2915 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2916 else
2917 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2919 else if (!isInit && !isFinal)
2920 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2921 else
2922 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2924 else if (char_count == 2)
2926 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2927 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2928 else if (!isInit)
2929 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2930 else
2931 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2933 else if (!isInit && !isFinal)
2934 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2935 else
2936 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2939 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2940 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2941 HeapFree(GetProcessHeap(),0,spaces);
2944 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 )
2946 int i,k;
2948 for (i = 0; i < cGlyphs; i++)
2950 int char_index[20];
2951 int char_count = 0;
2953 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2954 if (k>=0)
2956 for (; k < cChars && pwLogClust[k] == i; k++)
2957 char_index[char_count++] = k;
2960 if (char_count == 0)
2961 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2962 else
2964 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2965 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2966 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2970 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2971 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2974 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 )
2976 int i;
2977 int finaGlyph;
2978 INT dirL;
2980 if (!psa->fLogicalOrder && psa->fRTL)
2982 finaGlyph = 0;
2983 dirL = -1;
2985 else
2987 finaGlyph = cGlyphs-1;
2988 dirL = 1;
2991 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2993 for (i = 0; i < cGlyphs; i++)
2995 int k;
2996 int char_index[20];
2997 int char_count = 0;
2999 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3000 if (k>=0)
3002 for (; k < cChars && pwLogClust[k] == i; k++)
3003 char_index[char_count++] = k;
3006 if (i == finaGlyph)
3007 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3008 else
3009 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3011 if (char_count == 0)
3012 continue;
3014 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3015 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3017 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3018 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3019 pGlyphProp[i].sva.fClusterStart = 0;
3022 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3024 /* Do not allow justification between marks and their base */
3025 for (i = 0; i < cGlyphs; i++)
3027 if (!pGlyphProp[i].sva.fClusterStart)
3028 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3032 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)
3034 int i,k;
3036 for (i = 0; i < cGlyphs; i++)
3038 int char_index[20];
3039 int char_count = 0;
3041 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3042 if (k>=0)
3044 for (; k < cChars && pwLogClust[k] == i; k++)
3045 char_index[char_count++] = k;
3048 if (char_count == 0)
3049 continue;
3051 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3053 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3054 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3056 else
3057 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3059 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3060 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3063 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)
3065 int i,k;
3067 for (i = 0; i < cGlyphs; i++)
3069 int char_index[20];
3070 int char_count = 0;
3072 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3073 if (k>=0)
3075 for (; k < cChars && pwLogClust[k] == i; k++)
3076 char_index[char_count++] = k;
3079 if (char_count == 0)
3080 continue;
3082 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3084 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3085 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3087 else
3088 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3090 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3091 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3093 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3094 for (i = 0; i < cGlyphs; i++)
3096 if (!pGlyphProp[i].sva.fClusterStart)
3098 pGlyphProp[i].sva.fDiacritic = 0;
3099 pGlyphProp[i].sva.fZeroWidth = 0;
3104 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)
3106 int i,k;
3108 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3109 for (i = 0; i < cGlyphs; i++)
3111 int char_index[20];
3112 int char_count = 0;
3114 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3115 if (k>=0)
3117 for (; k < cChars && pwLogClust[k] == i; k++)
3118 char_index[char_count++] = k;
3121 if (override_gsub)
3123 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3124 pGlyphProp[i].sva.fDiacritic = FALSE;
3125 pGlyphProp[i].sva.fZeroWidth = FALSE;
3128 if (char_count == 0)
3130 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3131 continue;
3134 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3136 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3137 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3139 else
3140 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3142 pGlyphProp[i].sva.fClusterStart = 0;
3143 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3144 switch (lexical(pwcChars[char_index[k]]))
3146 case lex_Matra_pre:
3147 case lex_Matra_post:
3148 case lex_Matra_above:
3149 case lex_Matra_below:
3150 case lex_Modifier:
3151 case lex_Halant:
3152 break;
3153 case lex_ZWJ:
3154 case lex_ZWNJ:
3155 /* check for dangling joiners */
3156 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3157 pGlyphProp[i].sva.fClusterStart = 1;
3158 else
3159 k = char_count;
3160 break;
3161 default:
3162 pGlyphProp[i].sva.fClusterStart = 1;
3163 break;
3167 if (use_syllables)
3169 IndicSyllable *syllables = NULL;
3170 int syllable_count = 0;
3171 BOOL modern = get_GSUB_Indic2(psa, psc);
3173 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3175 for (i = 0; i < syllable_count; i++)
3177 int j;
3178 WORD g = pwLogClust[syllables[i].start];
3179 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3181 if (pwLogClust[j] != g)
3183 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3184 pwLogClust[j] = g;
3189 HeapFree(GetProcessHeap(), 0, syllables);
3192 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3195 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 )
3197 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3200 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 )
3202 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3205 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 )
3207 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3210 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 )
3212 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3215 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 )
3217 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3220 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 )
3222 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3225 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 )
3227 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3230 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 )
3232 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3235 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 )
3237 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3240 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 )
3242 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3245 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 )
3247 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3250 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)
3252 load_ot_tables(hdc, psc);
3254 if (ShapingData[psa->eScript].charGlyphPropProc)
3255 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3256 else
3257 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3260 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3262 load_ot_tables(hdc, psc);
3264 if (ShapingData[psa->eScript].contextProc)
3265 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3268 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)
3270 int i;
3271 INT dirL;
3273 if (!rpRangeProperties)
3274 return;
3276 load_ot_tables(hdc, psc);
3278 if (!psc->GSUB_Table)
3279 return;
3281 if (!psa->fLogicalOrder && psa->fRTL)
3282 dirL = -1;
3283 else
3284 dirL = 1;
3286 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3288 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3289 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3293 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3295 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3296 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3298 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3301 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3303 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3304 int i;
3306 rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3308 if (!rpRangeProperties)
3309 return;
3311 load_ot_tables(hdc, psc);
3313 if (!psc->GPOS_Table || !psc->otm)
3314 return;
3316 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3318 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3320 LoadedFeature *feature;
3322 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3323 if (!feature)
3324 continue;
3326 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3331 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3333 LoadedFeature *feature;
3334 int i;
3336 if (!ShapingData[psa->eScript].requiredFeatures)
3337 return S_OK;
3339 load_ot_tables(hdc, psc);
3341 /* we need to have at least one of the required features */
3342 i = 0;
3343 while (ShapingData[psa->eScript].requiredFeatures[i])
3345 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3346 if (feature)
3347 return S_OK;
3348 i++;
3351 return USP_E_SCRIPT_NOT_IN_FONT;
3354 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3355 SCRIPT_ANALYSIS *psa, int cMaxTags,
3356 OPENTYPE_TAG *pScriptTags, int *pcTags)
3358 HRESULT hr;
3359 OPENTYPE_TAG searching = 0x00000000;
3361 load_ot_tables(hdc, psc);
3363 if (psa && scriptInformation[psa->eScript].scriptTag)
3364 searching = scriptInformation[psa->eScript].scriptTag;
3366 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3367 if (FAILED(hr))
3368 *pcTags = 0;
3369 return hr;
3372 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3373 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3374 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3375 int *pcTags)
3377 HRESULT hr;
3378 OPENTYPE_TAG searching = 0x00000000;
3379 BOOL fellback = FALSE;
3381 load_ot_tables(hdc, psc);
3383 if (psa && psc->userLang != 0)
3384 searching = psc->userLang;
3386 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3387 if (FAILED(hr))
3389 fellback = TRUE;
3390 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3393 if (FAILED(hr) || fellback)
3394 *pcTags = 0;
3395 if (SUCCEEDED(hr) && fellback && psa)
3396 hr = E_INVALIDARG;
3397 return hr;
3400 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3401 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3402 OPENTYPE_TAG tagLangSys, int cMaxTags,
3403 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3405 HRESULT hr;
3406 BOOL filter = FALSE;
3408 load_ot_tables(hdc, psc);
3410 if (psa && scriptInformation[psa->eScript].scriptTag)
3412 FIXME("Filtering not implemented\n");
3413 filter = TRUE;
3416 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3418 if (FAILED(hr))
3419 *pcTags = 0;
3420 return hr;