usp10: Fix Contextual Shaping for Languages with RTL write order.
[wine.git] / dlls / usp10 / shape.c
blob850e9291ed15288bc06372f9e63b8af64b6c23ba
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #define FIRST_ARABIC_CHAR 0x0600
39 #define LAST_ARABIC_CHAR 0x06ff
41 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
42 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
63 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
65 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
67 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
68 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
73 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
75 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
76 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
77 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
78 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
79 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
80 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
81 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
82 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
83 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
84 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
85 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
87 extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
88 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
89 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
91 enum joining_types {
92 jtU,
93 jtT,
94 jtR,
95 jtL,
96 jtD,
97 jtC
100 enum joined_forms {
101 Xn=0,
105 /* Syriac Alaph */
106 Afj,
107 Afn,
111 typedef struct tagVowelComponents
113 WCHAR base;
114 WCHAR parts[3];
115 } VowelComponents;
117 typedef struct tagConsonantComponents
119 WCHAR parts[3];
120 WCHAR output;
121 } ConsonantComponents;
123 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
125 typedef int (*combining_lexical_function)(WCHAR c);
127 /* the orders of joined_forms and contextual_features need to line up */
128 static const char* contextual_features[] =
130 "isol",
131 "fina",
132 "init",
133 "medi",
134 /* Syriac Alaph */
135 "med2",
136 "fin2",
137 "fin3"
140 static OPENTYPE_FEATURE_RECORD standard_features[] =
142 { MS_MAKE_TAG('c','c','m','p'), 1},
143 { MS_MAKE_TAG('l','o','c','l'), 1},
146 static OPENTYPE_FEATURE_RECORD latin_features[] =
148 { MS_MAKE_TAG('l','o','c','l'), 1},
149 { MS_MAKE_TAG('c','c','m','p'), 1},
150 { MS_MAKE_TAG('l','i','g','a'), 1},
151 { MS_MAKE_TAG('c','l','i','g'), 1},
154 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
156 { MS_MAKE_TAG('k','e','r','n'), 1},
157 { MS_MAKE_TAG('m','a','r','k'), 1},
158 { MS_MAKE_TAG('m','k','m','k'), 1},
161 static OPENTYPE_FEATURE_RECORD arabic_features[] =
163 { MS_MAKE_TAG('r','l','i','g'), 1},
164 { MS_MAKE_TAG('c','a','l','t'), 1},
165 { MS_MAKE_TAG('l','i','g','a'), 1},
166 { MS_MAKE_TAG('d','l','i','g'), 1},
167 { MS_MAKE_TAG('c','s','w','h'), 1},
168 { MS_MAKE_TAG('m','s','e','t'), 1},
171 static const char* required_arabic_features[] =
173 "fina",
174 "init",
175 "medi",
176 "rlig",
177 NULL
180 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
182 { MS_MAKE_TAG('c','u','r','s'), 1},
183 { MS_MAKE_TAG('k','e','r','n'), 1},
184 { MS_MAKE_TAG('m','a','r','k'), 1},
185 { MS_MAKE_TAG('m','k','m','k'), 1},
188 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
190 { MS_MAKE_TAG('c','c','m','p'), 1},
191 { MS_MAKE_TAG('d','l','i','g'), 0},
194 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
196 { MS_MAKE_TAG('k','e','r','n'), 1},
197 { MS_MAKE_TAG('m','a','r','k'), 1},
200 static OPENTYPE_FEATURE_RECORD syriac_features[] =
202 { MS_MAKE_TAG('r','l','i','g'), 1},
203 { MS_MAKE_TAG('c','a','l','t'), 1},
204 { MS_MAKE_TAG('l','i','g','a'), 1},
205 { MS_MAKE_TAG('d','l','i','g'), 1},
208 static const char* required_syriac_features[] =
210 "fina",
211 "fin2",
212 "fin3",
213 "init",
214 "medi",
215 "med2",
216 "rlig",
217 NULL
220 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
222 { MS_MAKE_TAG('k','e','r','n'), 1},
223 { MS_MAKE_TAG('m','a','r','k'), 1},
224 { MS_MAKE_TAG('m','k','m','k'), 1},
227 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
229 /* Presentation forms */
230 { MS_MAKE_TAG('b','l','w','s'), 1},
231 { MS_MAKE_TAG('a','b','v','s'), 1},
232 { MS_MAKE_TAG('p','s','t','s'), 1},
235 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
237 { MS_MAKE_TAG('a','b','v','s'), 1},
238 { MS_MAKE_TAG('b','l','w','s'), 1},
241 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
243 { MS_MAKE_TAG('a','b','v','m'), 1},
244 { MS_MAKE_TAG('b','l','w','m'), 1},
247 static OPENTYPE_FEATURE_RECORD phags_features[] =
249 { MS_MAKE_TAG('a','b','v','s'), 1},
250 { MS_MAKE_TAG('b','l','w','s'), 1},
251 { MS_MAKE_TAG('c','a','l','t'), 1},
254 static OPENTYPE_FEATURE_RECORD thai_features[] =
256 { MS_MAKE_TAG('c','c','m','p'), 1},
259 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
261 { MS_MAKE_TAG('k','e','r','n'), 1},
262 { MS_MAKE_TAG('m','a','r','k'), 1},
263 { MS_MAKE_TAG('m','k','m','k'), 1},
266 static const char* required_lao_features[] =
268 "ccmp",
269 NULL
272 static const char* required_devanagari_features[] =
274 "nukt",
275 "akhn",
276 "rphf",
277 "blwf",
278 "half",
279 "vatu",
280 "pres",
281 "abvs",
282 "blws",
283 "psts",
284 "haln",
285 NULL
288 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
290 { MS_MAKE_TAG('p','r','e','s'), 1},
291 { MS_MAKE_TAG('a','b','v','s'), 1},
292 { MS_MAKE_TAG('b','l','w','s'), 1},
293 { MS_MAKE_TAG('p','s','t','s'), 1},
294 { MS_MAKE_TAG('h','a','l','n'), 1},
295 { MS_MAKE_TAG('c','a','l','t'), 1},
298 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
300 { MS_MAKE_TAG('k','e','r','n'), 1},
301 { MS_MAKE_TAG('d','i','s','t'), 1},
302 { MS_MAKE_TAG('a','b','v','m'), 1},
303 { MS_MAKE_TAG('b','l','w','m'), 1},
306 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
308 { MS_MAKE_TAG('l','i','g','a'), 1},
309 { MS_MAKE_TAG('c','l','i','g'), 1},
312 static const char* required_bengali_features[] =
314 "nukt",
315 "akhn",
316 "rphf",
317 "blwf",
318 "half",
319 "vatu",
320 "pstf",
321 "init",
322 "abvs",
323 "blws",
324 "psts",
325 "haln",
326 NULL
329 static const char* required_gurmukhi_features[] =
331 "nukt",
332 "akhn",
333 "rphf",
334 "blwf",
335 "half",
336 "pstf",
337 "vatu",
338 "cjct",
339 "pres",
340 "abvs",
341 "blws",
342 "psts",
343 "haln",
344 "calt",
345 NULL
348 static const char* required_oriya_features[] =
350 "nukt",
351 "akhn",
352 "rphf",
353 "blwf",
354 "pstf",
355 "cjct",
356 "pres",
357 "abvs",
358 "blws",
359 "psts",
360 "haln",
361 "calt",
362 NULL
365 static const char* required_tamil_features[] =
367 "nukt",
368 "akhn",
369 "rphf",
370 "pref",
371 "half",
372 "pres",
373 "abvs",
374 "blws",
375 "psts",
376 "haln",
377 "calt",
378 NULL
381 static const char* required_telugu_features[] =
383 "nukt",
384 "akhn",
385 "rphf",
386 "pref",
387 "half",
388 "pstf",
389 "cjct",
390 "pres",
391 "abvs",
392 "blws",
393 "psts",
394 "haln",
395 "calt",
396 NULL
399 static OPENTYPE_FEATURE_RECORD khmer_features[] =
401 { MS_MAKE_TAG('p','r','e','s'), 1},
402 { MS_MAKE_TAG('b','l','w','s'), 1},
403 { MS_MAKE_TAG('a','b','v','s'), 1},
404 { MS_MAKE_TAG('p','s','t','s'), 1},
405 { MS_MAKE_TAG('c','l','i','g'), 1},
408 static const char* required_khmer_features[] =
410 "pref",
411 "blwf",
412 "abvf",
413 "pstf",
414 "pres",
415 "blws",
416 "abvs",
417 "psts",
418 "clig",
419 NULL
422 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
424 { MS_MAKE_TAG('d','i','s','t'), 1},
425 { MS_MAKE_TAG('b','l','w','m'), 1},
426 { MS_MAKE_TAG('a','b','v','m'), 1},
427 { MS_MAKE_TAG('m','k','m','k'), 1},
430 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
432 { MS_MAKE_TAG('c','c','m','p'), 1},
433 { MS_MAKE_TAG('l','o','c','l'), 1},
434 { MS_MAKE_TAG('c','a','l','t'), 1},
435 { MS_MAKE_TAG('l','i','g','a'), 1},
438 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
440 { MS_MAKE_TAG('c','c','m','p'), 1},
441 { MS_MAKE_TAG('l','o','c','l'), 1},
442 { MS_MAKE_TAG('c','a','l','t'), 1},
443 { MS_MAKE_TAG('r','l','i','g'), 1},
446 typedef struct ScriptShapeDataTag {
447 TEXTRANGE_PROPERTIES defaultTextRange;
448 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
449 const char** requiredFeatures;
450 OPENTYPE_TAG newOtTag;
451 ContextualShapingProc contextProc;
452 ShapeCharGlyphPropProc charGlyphPropProc;
453 } ScriptShapeData;
455 /* in order of scripts */
456 static const ScriptShapeData ShapingData[] =
458 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
459 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
460 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
461 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
462 {{ standard_features, 2}, {NULL, 0}, NULL, 0, ContextualShape_Control, ShapeCharGlyphProp_Control},
463 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
464 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
465 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
466 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
467 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
468 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
469 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
470 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
471 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
472 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
473 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
474 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
475 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
476 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
477 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
478 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
479 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
480 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
481 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
482 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
483 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
497 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
498 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
499 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
500 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
501 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
502 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
503 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
504 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
505 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
506 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
511 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
512 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
513 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
516 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
521 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
522 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
523 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
524 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
526 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
527 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
528 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
529 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
530 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
531 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
532 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
533 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
534 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
535 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
536 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
537 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
538 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
539 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
542 extern scriptData scriptInformation[];
544 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
546 int i;
547 int out_index = GSUB_E_NOGLYPH;
549 TRACE("%i lookups\n", feature->lookup_count);
550 for (i = 0; i < feature->lookup_count; i++)
552 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
553 if (out_index != GSUB_E_NOGLYPH)
554 break;
556 if (out_index == GSUB_E_NOGLYPH)
557 TRACE("lookups found no glyphs\n");
558 else
560 int out2;
561 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
562 if (out2!=GSUB_E_NOGLYPH)
563 out_index = out2;
565 return out_index;
568 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
570 UINT charset;
572 if (psc->userScript != 0)
574 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
575 return ShapingData[psa->eScript].newOtTag;
576 else
577 return psc->userScript;
580 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
581 return ShapingData[psa->eScript].newOtTag;
583 if (scriptInformation[psa->eScript].scriptTag)
584 return scriptInformation[psa->eScript].scriptTag;
587 * fall back to the font charset
589 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
590 switch (charset)
592 case ANSI_CHARSET:
593 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
594 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
595 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
596 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
597 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
598 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
599 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
600 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
601 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
602 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
603 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
604 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
605 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
606 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
607 default: return MS_MAKE_TAG('l','a','t','n');
611 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
613 LoadedFeature *feature = NULL;
615 if (psc->GSUB_Table || psc->GPOS_Table)
617 int attempt = 2;
618 OPENTYPE_TAG tags;
619 OPENTYPE_TAG language;
620 OPENTYPE_TAG script = 0x00000000;
621 int cTags;
625 script = get_opentype_script(hdc,psa,psc,(attempt==2));
626 if (psc->userLang != 0)
627 language = psc->userLang;
628 else
629 language = MS_MAKE_TAG('d','f','l','t');
630 attempt--;
632 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
634 } while(attempt && !feature);
636 /* try in the default (latin) table */
637 if (!feature && !script)
638 OpenType_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
641 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
642 return feature;
645 static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *glyphs, INT index, INT write_dir, INT* glyph_count, const char* feat)
647 LoadedFeature *feature;
649 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
650 if (!feature)
651 return GSUB_E_NOFEATURE;
653 TRACE("applying feature %s\n",feat);
654 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
657 static VOID *load_gsub_table(HDC hdc)
659 VOID* GSUB_Table = NULL;
660 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
661 if (length != GDI_ERROR)
663 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
664 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
665 TRACE("Loaded GSUB table of %i bytes\n",length);
667 return GSUB_Table;
670 static VOID *load_gpos_table(HDC hdc)
672 VOID* GPOS_Table = NULL;
673 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
674 if (length != GDI_ERROR)
676 GPOS_Table = HeapAlloc(GetProcessHeap(),0,length);
677 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
678 TRACE("Loaded GPOS table of %i bytes\n",length);
680 return GPOS_Table;
683 static VOID *load_gdef_table(HDC hdc)
685 VOID* GDEF_Table = NULL;
686 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
687 if (length != GDI_ERROR)
689 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
690 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
691 TRACE("Loaded GDEF table of %i bytes\n",length);
693 return GDEF_Table;
696 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
698 if (!psc->GSUB_Table)
699 psc->GSUB_Table = load_gsub_table(hdc);
700 if (!psc->GPOS_Table)
701 psc->GPOS_Table = load_gpos_table(hdc);
702 if (!psc->GDEF_Table)
703 psc->GDEF_Table = load_gdef_table(hdc);
706 INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature)
708 WORD *glyphs;
709 INT glyph_count = count;
710 INT rc;
712 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
713 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
714 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
715 if (rc > GSUB_E_NOGLYPH)
716 rc = count - glyph_count;
717 else
718 rc = 0;
720 HeapFree(GetProcessHeap(),0,glyphs);
721 return rc;
724 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
726 int i;
728 for (i = 0; i < cGlyphs; i++)
730 if (!pGlyphProp[i].sva.fClusterStart)
732 int j;
733 for (j = 0; j < cChars; j++)
735 if (pwLogClust[j] == i)
737 int k = j;
738 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
739 k-=1;
740 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
741 pwLogClust[j] = pwLogClust[k];
748 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
750 if (changeCount == 0)
751 return;
752 else
754 int i;
755 int target_glyph = nextIndex - write_dir;
756 int seeking_glyph;
757 int target_index = -1;
758 int replacing_glyph = -1;
759 int changed = 0;
760 int top_logclust = 0;
762 if (changeCount > 0)
764 if (write_dir > 0)
765 target_glyph = nextIndex - changeCount;
766 else
767 target_glyph = nextIndex + (changeCount + 1);
770 seeking_glyph = target_glyph;
771 for (i = 0; i < chars; i++)
772 if (pwLogClust[i] > top_logclust)
773 top_logclust = pwLogClust[i];
775 do {
776 if (write_dir > 0)
777 for (i = 0; i < chars; i++)
779 if (pwLogClust[i] == seeking_glyph)
781 target_index = i;
782 break;
785 else
786 for (i = chars - 1; i >= 0; i--)
788 if (pwLogClust[i] == seeking_glyph)
790 target_index = i;
791 break;
794 if (target_index == -1)
795 seeking_glyph ++;
797 while (target_index == -1 && seeking_glyph <= top_logclust);
799 if (target_index == -1)
801 ERR("Unable to find target glyph\n");
802 return;
805 if (changeCount < 0)
807 /* merge glyphs */
808 for(i = target_index; i < chars && i >= 0; i+=write_dir)
810 if (pwLogClust[i] == target_glyph)
811 continue;
812 if(pwLogClust[i] == replacing_glyph)
813 pwLogClust[i] = target_glyph;
814 else
816 changed--;
817 if (changed >= changeCount)
819 replacing_glyph = pwLogClust[i];
820 pwLogClust[i] = target_glyph;
822 else
823 break;
827 /* renumber trailing indexes*/
828 for(i = target_index; i < chars && i >= 0; i+=write_dir)
830 if (pwLogClust[i] != target_glyph)
831 pwLogClust[i] += changeCount;
834 else
836 for(i = target_index; i < chars && i >= 0; i+=write_dir)
837 pwLogClust[i] += changeCount;
842 static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *pwOutGlyphs, int write_dir, INT* pcGlyphs, INT cChars, const char* feat, WORD *pwLogClust )
844 if (psc->GSUB_Table)
846 LoadedFeature *feature;
847 int lookup_index;
849 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
850 if (!feature)
851 return GSUB_E_NOFEATURE;
853 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
854 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
856 int i;
858 if (write_dir > 0)
859 i = 0;
860 else
861 i = *pcGlyphs-1;
862 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
863 while(i < *pcGlyphs && i >= 0)
865 INT nextIndex;
866 INT prevCount = *pcGlyphs;
868 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
869 if (*pcGlyphs != prevCount)
871 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
872 i = nextIndex;
874 else
875 i+=write_dir;
878 return *pcGlyphs;
880 return GSUB_E_NOFEATURE;
883 static VOID GPOS_apply_feature(ScriptCache *psc, LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, const SCRIPT_ANALYSIS *analysis, INT* piAdvance, LoadedFeature *feature, const WORD *glyphs, INT glyph_count, GOFFSET *pGoffset)
885 int i;
887 TRACE("%i lookups\n", feature->lookup_count);
888 for (i = 0; i < feature->lookup_count; i++)
890 int j;
891 for (j = 0; j < glyph_count; )
892 j = OpenType_apply_GPOS_lookup(psc, lpotm, lplogfont, analysis, piAdvance, feature->lookups[i], glyphs, j, glyph_count, pGoffset);
896 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
898 OPENTYPE_TAG tag;
899 HRESULT hr;
900 int count = 0;
902 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
904 return(SUCCEEDED(hr));
907 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
909 int i;
910 for (i = *pcGlyphs; i>=index; i--)
911 pwGlyphs[i+1] = pwGlyphs[i];
912 pwGlyphs[index] = glyph;
913 *pcGlyphs = *pcGlyphs+1;
914 if (write_dir < 0)
915 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
916 else
917 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
920 static void mark_invalid_combinations(HDC hdc, const WCHAR* pwcChars, INT cChars, WORD *pwGlyphs, INT *pcGlyphs, INT write_dir, WORD *pwLogClust, combining_lexical_function lex)
922 CHAR *context_type;
923 int i,g;
924 WCHAR invalid = 0x25cc;
925 WORD invalid_glyph;
927 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
929 /* Mark invalid combinations */
930 for (i = 0; i < cChars; i++)
931 context_type[i] = lex(pwcChars[i]);
933 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
934 for (i = 1, g=1; i < cChars - 1; i++, g++)
936 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
938 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
939 g++;
943 HeapFree(GetProcessHeap(),0,context_type);
946 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
948 int i;
949 for (i=0; i < cChars; i++)
951 switch (pwcChars[i])
953 case 0x000A:
954 case 0x000D:
955 pwOutGlyphs[i] = psc->sfp.wgBlank;
956 break;
957 default:
958 if (pwcChars[i] < 0x1C)
959 pwOutGlyphs[i] = psc->sfp.wgDefault;
960 else
961 pwOutGlyphs[i] = psc->sfp.wgBlank;
966 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
968 if (i + delta < 0)
969 return 0;
970 if ( i+ delta >= cchLen)
971 return 0;
973 i += delta;
975 return chars[i];
978 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
980 if (i + delta < 0)
982 if (psa->fLinkBefore)
983 return jtR;
984 else
985 return jtU;
987 if ( i+ delta >= cchLen)
989 if (psa->fLinkAfter)
990 return jtL;
991 else
992 return jtU;
995 i += delta;
997 if (context_type[i] == jtT)
998 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
999 else
1000 return context_type[i];
1003 static inline BOOL right_join_causing(CHAR joining_type)
1005 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1008 static inline BOOL left_join_causing(CHAR joining_type)
1010 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1013 static inline BOOL word_break_causing(WCHAR chr)
1015 /* we are working within a string of characters already guareented to
1016 be within one script, Syriac, so we do not worry about any character
1017 other than the space character outside of that range */
1018 return (chr == 0 || chr == 0x20 );
1021 static int combining_lexical_Arabic(WCHAR c)
1023 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1025 switch(c)
1027 case 0x064B:
1028 case 0x064C:
1029 case 0x064E:
1030 case 0x064F:
1031 case 0x0652:
1032 case 0x0657:
1033 case 0x0658:
1034 case 0x06E1: return Arab_DIAC1;
1035 case 0x064D:
1036 case 0x0650:
1037 case 0x0656: return Arab_DIAC2;
1038 case 0x0651: return Arab_DIAC3;
1039 case 0x0610:
1040 case 0x0611:
1041 case 0x0612:
1042 case 0x0613:
1043 case 0x0614:
1044 case 0x0659:
1045 case 0x06D6:
1046 case 0x06DC:
1047 case 0x06DF:
1048 case 0x06E0:
1049 case 0x06E2:
1050 case 0x06E4:
1051 case 0x06E7:
1052 case 0x06E8:
1053 case 0x06EB:
1054 case 0x06EC: return Arab_DIAC4;
1055 case 0x06E3:
1056 case 0x06EA:
1057 case 0x06ED: return Arab_DIAC5;
1058 case 0x0670: return Arab_DIAC6;
1059 case 0x0653: return Arab_DIAC7;
1060 case 0x0655:
1061 case 0x0654: return Arab_DIAC8;
1062 default: return Arab_Norm;
1067 * ContextualShape_Arabic
1069 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1071 CHAR *context_type;
1072 INT *context_shape;
1073 INT dirR, dirL;
1074 int i;
1075 int char_index;
1076 int glyph_index;
1078 if (*pcGlyphs != cChars)
1080 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1081 return;
1084 if (!psa->fLogicalOrder && psa->fRTL)
1086 dirR = 1;
1087 dirL = -1;
1089 else
1091 dirR = -1;
1092 dirL = 1;
1095 load_ot_tables(hdc, psc);
1097 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1098 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1100 for (i = 0; i < cChars; i++)
1101 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1103 for (i = 0; i < cChars; i++)
1105 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1106 context_shape[i] = Xr;
1107 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1108 context_shape[i] = Xl;
1109 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)))
1110 context_shape[i] = Xm;
1111 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1112 context_shape[i] = Xr;
1113 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1114 context_shape[i] = Xl;
1115 else
1116 context_shape[i] = Xn;
1119 /* Contextual Shaping */
1120 if (dirL > 0)
1121 char_index = glyph_index = 0;
1122 else
1123 char_index = glyph_index = cChars-1;
1125 while(char_index < cChars && char_index >= 0)
1127 BOOL shaped = FALSE;
1129 if (psc->GSUB_Table)
1131 INT nextIndex;
1132 INT prevCount = *pcGlyphs;
1134 /* Apply the contextual feature */
1135 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1137 if (nextIndex > GSUB_E_NOGLYPH)
1139 UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1140 char_index += dirL;
1141 glyph_index = nextIndex;
1143 shaped = (nextIndex > GSUB_E_NOGLYPH);
1146 if (!shaped)
1148 if (context_shape[char_index] == Xn)
1150 WORD newGlyph = pwOutGlyphs[glyph_index];
1151 if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
1153 /* fall back to presentation form B */
1154 WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
1155 if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1156 pwOutGlyphs[glyph_index] = newGlyph;
1159 char_index += dirL;
1160 glyph_index += dirL;
1164 HeapFree(GetProcessHeap(),0,context_shape);
1165 HeapFree(GetProcessHeap(),0,context_type);
1167 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1170 static int combining_lexical_Hebrew(WCHAR c)
1172 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};
1174 switch(c)
1176 case 0x05B0:
1177 case 0x05B1:
1178 case 0x05B2:
1179 case 0x05B3:
1180 case 0x05B4:
1181 case 0x05B5:
1182 case 0x05B6:
1183 case 0x05BB: return Hebr_DIAC;
1184 case 0x0599:
1185 case 0x05A1:
1186 case 0x05A9:
1187 case 0x05AE: return Hebr_CANT1;
1188 case 0x0597:
1189 case 0x05A8:
1190 case 0x05AC: return Hebr_CANT2;
1191 case 0x0592:
1192 case 0x0593:
1193 case 0x0594:
1194 case 0x0595:
1195 case 0x05A7:
1196 case 0x05AB: return Hebr_CANT3;
1197 case 0x0598:
1198 case 0x059C:
1199 case 0x059E:
1200 case 0x059F: return Hebr_CANT4;
1201 case 0x059D:
1202 case 0x05A0: return Hebr_CANT5;
1203 case 0x059B:
1204 case 0x05A5: return Hebr_CANT6;
1205 case 0x0591:
1206 case 0x05A3:
1207 case 0x05A6: return Hebr_CANT7;
1208 case 0x0596:
1209 case 0x05A4:
1210 case 0x05AA: return Hebr_CANT8;
1211 case 0x059A:
1212 case 0x05AD: return Hebr_CANT9;
1213 case 0x05AF: return Hebr_CANT10;
1214 case 0x05BC: return Hebr_DAGESH;
1215 case 0x05C4: return Hebr_DOTABV;
1216 case 0x05B9: return Hebr_HOLAM;
1217 case 0x05BD: return Hebr_METEG;
1218 case 0x05B7: return Hebr_PATAH;
1219 case 0x05B8: return Hebr_QAMATS;
1220 case 0x05BF: return Hebr_RAFE;
1221 case 0x05C1:
1222 case 0x05C2: return Hebr_SHINSIN;
1223 default: return Hebr_Norm;
1227 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1229 INT dirL;
1231 if (*pcGlyphs != cChars)
1233 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1234 return;
1237 if (!psa->fLogicalOrder && psa->fRTL)
1238 dirL = -1;
1239 else
1240 dirL = 1;
1242 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1246 * ContextualShape_Syriac
1249 static int combining_lexical_Syriac(WCHAR c)
1251 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};
1253 switch(c)
1255 case 0x730:
1256 case 0x733:
1257 case 0x736:
1258 case 0x73A:
1259 case 0x73D: return Syriac_DIAC1;
1260 case 0x731:
1261 case 0x734:
1262 case 0x737:
1263 case 0x73B:
1264 case 0x73E: return Syriac_DIAC2;
1265 case 0x740:
1266 case 0x749:
1267 case 0x74A: return Syriac_DIAC3;
1268 case 0x732:
1269 case 0x735:
1270 case 0x73F: return Syriac_DIAC4;
1271 case 0x738:
1272 case 0x739:
1273 case 0x73C: return Syriac_DIAC5;
1274 case 0x741:
1275 case 0x30A: return Syriac_DIAC6;
1276 case 0x742:
1277 case 0x325: return Syriac_DIAC7;
1278 case 0x747:
1279 case 0x303: return Syriac_DIAC8;
1280 case 0x748:
1281 case 0x32D:
1282 case 0x32E:
1283 case 0x330:
1284 case 0x331: return Syriac_DIAC9;
1285 case 0x308: return Syriac_DIAC10;
1286 case 0x304: return Syriac_DIAC11;
1287 case 0x307: return Syriac_DIAC12;
1288 case 0x323: return Syriac_DIAC13;
1289 case 0x743: return Syriac_DIAC14;
1290 case 0x744: return Syriac_DIAC15;
1291 case 0x745: return Syriac_DIAC16;
1292 case 0x746: return Syriac_DIAC17;
1293 default: return Syriac_Norm;
1297 #define ALAPH 0x710
1298 #define DALATH 0x715
1299 #define RISH 0x72A
1301 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1303 CHAR *context_type;
1304 INT *context_shape;
1305 INT dirR, dirL;
1306 int i;
1307 int char_index;
1308 int glyph_index;
1310 if (*pcGlyphs != cChars)
1312 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1313 return;
1316 if (!psa->fLogicalOrder && psa->fRTL)
1318 dirR = 1;
1319 dirL = -1;
1321 else
1323 dirR = -1;
1324 dirL = 1;
1327 load_ot_tables(hdc, psc);
1329 if (!psc->GSUB_Table)
1330 return;
1332 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1333 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1335 for (i = 0; i < cChars; i++)
1336 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1338 for (i = 0; i < cChars; i++)
1340 if (pwcChars[i] == ALAPH)
1342 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1344 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1345 context_shape[i] = Afj;
1346 else if ( rchar != DALATH && rchar != RISH &&
1347 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1348 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1349 context_shape[i] = Afn;
1350 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1351 context_shape[i] = Afx;
1352 else
1353 context_shape[i] = Xn;
1355 else if (context_type[i] == jtR &&
1356 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1357 context_shape[i] = Xr;
1358 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1359 context_shape[i] = Xl;
1360 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)))
1361 context_shape[i] = Xm;
1362 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1363 context_shape[i] = Xr;
1364 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1365 context_shape[i] = Xl;
1366 else
1367 context_shape[i] = Xn;
1370 /* Contextual Shaping */
1371 if (dirL > 0)
1372 char_index = glyph_index = 0;
1373 else
1374 char_index = glyph_index = cChars-1;
1376 while(char_index < cChars && char_index >= 0)
1378 INT nextIndex, offset = 0;
1379 INT prevCount = *pcGlyphs;
1381 /* Apply CCMP first */
1382 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1384 if (prevCount != *pcGlyphs)
1386 offset = *pcGlyphs - prevCount;
1387 if (dirL < 0)
1388 glyph_index -= offset * dirL;
1391 /* Apply the contextual feature */
1392 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1393 if (nextIndex > GSUB_E_NOGLYPH)
1395 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1396 char_index += dirL;
1397 if (!offset)
1398 glyph_index = nextIndex;
1399 else
1401 offset = *pcGlyphs - prevCount;
1402 glyph_index += dirL * (offset + 1);
1405 else
1407 char_index += dirL;
1408 glyph_index += dirL;
1412 HeapFree(GetProcessHeap(),0,context_shape);
1413 HeapFree(GetProcessHeap(),0,context_type);
1415 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1418 static int combining_lexical_Thaana(WCHAR c)
1420 enum {Thaana_Norm=0, Thaana_FILI};
1422 switch(c)
1424 case 0x7A6:
1425 case 0x7A7:
1426 case 0x7A8:
1427 case 0x7A9:
1428 case 0x7AA:
1429 case 0x7AB:
1430 case 0x7AC:
1431 case 0x7AD:
1432 case 0x7AE:
1433 case 0x7AF: return Thaana_FILI;
1434 default: return Thaana_Norm;
1438 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1440 INT dirL;
1442 if (*pcGlyphs != cChars)
1444 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1445 return;
1448 if (!psa->fLogicalOrder && psa->fRTL)
1449 dirL = -1;
1450 else
1451 dirL = 1;
1453 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1457 * ContextualShape_Phags_pa
1460 #define phags_pa_CANDRABINDU 0xA873
1461 #define phags_pa_START 0xA840
1462 #define phags_pa_END 0xA87F
1464 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1466 INT *context_shape;
1467 INT dirR, dirL;
1468 int i;
1469 int char_index;
1470 int glyph_index;
1472 if (*pcGlyphs != cChars)
1474 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1475 return;
1478 if (!psa->fLogicalOrder && psa->fRTL)
1480 dirR = 1;
1481 dirL = -1;
1483 else
1485 dirR = -1;
1486 dirL = 1;
1489 load_ot_tables(hdc, psc);
1491 if (!psc->GSUB_Table)
1492 return;
1494 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1496 for (i = 0; i < cChars; i++)
1498 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1500 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1501 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1502 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1503 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1505 if (jrchar && jlchar)
1506 context_shape[i] = Xm;
1507 else if (jrchar)
1508 context_shape[i] = Xr;
1509 else if (jlchar)
1510 context_shape[i] = Xl;
1511 else
1512 context_shape[i] = Xn;
1514 else
1515 context_shape[i] = -1;
1518 /* Contextual Shaping */
1519 if (dirL > 0)
1520 char_index = glyph_index = 0;
1521 else
1522 char_index = glyph_index = cChars-1;
1524 while(char_index < cChars && char_index >= 0)
1526 if (context_shape[char_index] >= 0)
1528 INT nextIndex;
1529 INT prevCount = *pcGlyphs;
1530 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1532 if (nextIndex > GSUB_E_NOGLYPH)
1534 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1535 glyph_index = nextIndex;
1536 char_index += dirL;
1538 else
1540 char_index += dirL;
1541 glyph_index += dirL;
1544 else
1546 char_index += dirL;
1547 glyph_index += dirL;
1551 HeapFree(GetProcessHeap(),0,context_shape);
1554 static int combining_lexical_Thai(WCHAR c)
1556 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1558 switch(c)
1560 case 0xE31:
1561 case 0xE34:
1562 case 0xE35:
1563 case 0xE36:
1564 case 0xE37: return Thai_ABOVE1;
1565 case 0xE47:
1566 case 0xE4D: return Thai_ABOVE2;
1567 case 0xE48:
1568 case 0xE49:
1569 case 0xE4A:
1570 case 0xE4B: return Thai_ABOVE3;
1571 case 0xE4C:
1572 case 0xE4E: return Thai_ABOVE4;
1573 case 0xE38:
1574 case 0xE39: return Thai_BELOW1;
1575 case 0xE3A: return Thai_BELOW2;
1576 case 0xE33: return Thai_AM;
1577 default: return Thai_Norm;
1581 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1583 INT dirL;
1585 if (*pcGlyphs != cChars)
1587 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1588 return;
1591 if (!psa->fLogicalOrder && psa->fRTL)
1592 dirL = -1;
1593 else
1594 dirL = 1;
1596 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1599 static int combining_lexical_Lao(WCHAR c)
1601 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1603 switch(c)
1605 case 0xEB1:
1606 case 0xEB4:
1607 case 0xEB5:
1608 case 0xEB6:
1609 case 0xEB7:
1610 case 0xEBB:
1611 case 0xECD: return Lao_ABOVE1;
1612 case 0xEC8:
1613 case 0xEC9:
1614 case 0xECA:
1615 case 0xECB:
1616 case 0xECC: return Lao_ABOVE2;
1617 case 0xEBC: return Lao_BELOW1;
1618 case 0xEB8:
1619 case 0xEB9: return Lao_BELOW2;
1620 case 0xEB3: return Lao_AM;
1621 default: return Lao_Norm;
1625 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1627 INT dirL;
1629 if (*pcGlyphs != cChars)
1631 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1632 return;
1635 if (!psa->fLogicalOrder && psa->fRTL)
1636 dirL = -1;
1637 else
1638 dirL = 1;
1640 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1643 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1645 int i;
1647 /* Replace */
1648 pwOutChars[cWalk] = replacements[0];
1649 cWalk=cWalk+1;
1651 /* Insert */
1652 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1654 int j;
1655 for (j = *pcChars; j > cWalk; j--)
1656 pwOutChars[j] = pwOutChars[j-1];
1657 *pcChars= *pcChars+1;
1658 pwOutChars[cWalk] = replacements[i];
1659 cWalk = cWalk+1;
1663 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1665 int i;
1666 int cWalk;
1668 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1670 for (i = 0; vowels[i].base != 0x0; i++)
1672 if (pwOutChars[cWalk] == vowels[i].base)
1674 int o = 0;
1675 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1676 if (vowels[i].parts[1]) { cWalk++; o++; }
1677 if (vowels[i].parts[2]) { cWalk++; o++; }
1678 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1679 break;
1685 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1687 int i;
1688 int offset = 0;
1689 int cWalk;
1691 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1693 for (i = 0; consonants[i].output!= 0x0; i++)
1695 int j;
1696 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1697 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1698 break;
1700 if (consonants[i].parts[j]==0x0) /* matched all */
1702 int k;
1703 j--;
1704 pwOutChars[cWalk] = consonants[i].output;
1705 for(k = cWalk+1; k < *pcChars - j; k++)
1706 pwOutChars[k] = pwOutChars[k+j];
1707 *pcChars = *pcChars - j;
1708 for (k = j ; k > 0; k--)
1709 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1710 offset += j;
1711 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1712 pwLogClust[k]--;
1713 break;
1716 cWalk++;
1720 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1722 if (s->ralf >= 0)
1724 int j;
1725 WORD Ra = pwChar[s->start];
1726 WORD H = pwChar[s->start+1];
1728 TRACE("Doing reorder of Ra to %i\n",s->base);
1729 for (j = s->start; j < s->base-1; j++)
1730 pwChar[j] = pwChar[j+2];
1731 pwChar[s->base-1] = Ra;
1732 pwChar[s->base] = H;
1734 s->ralf = s->base-1;
1735 s->base -= 2;
1739 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1741 if (s->ralf >= 0)
1743 int j,loc;
1744 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1745 WORD Ra = pwChar[s->start];
1746 WORD H = pwChar[s->start+1];
1747 for (loc = s->end; loc > stop; loc--)
1748 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1749 break;
1751 TRACE("Doing reorder of Ra to %i\n",loc);
1752 for (j = s->start; j < loc-1; j++)
1753 pwChar[j] = pwChar[j+2];
1754 pwChar[loc-1] = Ra;
1755 pwChar[loc] = H;
1757 s->ralf = loc-1;
1758 s->base -= 2;
1759 if (s->blwf >= 0) s->blwf -= 2;
1760 if (s->pref >= 0) s->pref -= 2;
1764 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1766 if (s->ralf >= 0)
1768 int j;
1769 WORD Ra = pwChar[s->start];
1770 WORD H = pwChar[s->start+1];
1772 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1773 for (j = s->start; j < s->end-1; j++)
1774 pwChar[j] = pwChar[j+2];
1775 pwChar[s->end-1] = Ra;
1776 pwChar[s->end] = H;
1778 s->ralf = s->end-1;
1779 s->base -= 2;
1780 if (s->blwf >= 0) s->blwf -= 2;
1781 if (s->pref >= 0) s->pref -= 2;
1785 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1787 int i;
1789 /* reorder Matras */
1790 if (s->end > s->base)
1792 for (i = 1; i <= s->end-s->base; i++)
1794 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1796 int j;
1797 WCHAR c = pwChar[s->base+i];
1798 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1799 for (j = s->base+i; j > s->base; j--)
1800 pwChar[j] = pwChar[j-1];
1801 pwChar[s->base] = c;
1803 if (s->ralf >= s->base) s->ralf++;
1804 if (s->blwf >= s->base) s->blwf++;
1805 if (s->pref >= s->base) s->pref++;
1806 s->base ++;
1812 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1814 int i;
1816 /* reorder Matras */
1817 if (s->end > s->base)
1819 for (i = 1; i <= s->end-s->base; i++)
1821 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1823 int j;
1824 WCHAR c = pwChar[s->base+i];
1825 TRACE("Doing reorder of %x to %i\n",c,s->start);
1826 for (j = s->base+i; j > s->start; j--)
1827 pwChar[j] = pwChar[j-1];
1828 pwChar[s->start] = c;
1830 if (s->ralf >= 0) s->ralf++;
1831 if (s->blwf >= 0) s->blwf++;
1832 if (s->pref >= 0) s->pref++;
1833 s->base ++;
1839 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1841 if (s->blwf >= 0 && g->blwf > g->base)
1843 int j,loc;
1844 int g_offset;
1845 for (loc = s->end; loc > s->blwf; loc--)
1846 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1847 break;
1849 g_offset = (loc - s->blwf) - 1;
1851 if (loc != s->blwf)
1853 WORD blwf = glyphs[g->blwf];
1854 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1855 /* do not care about the pwChar array anymore, just the glyphs */
1856 for (j = 0; j < g_offset; j++)
1857 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1858 glyphs[g->blwf + g_offset] = blwf;
1863 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1865 int i;
1867 /* reorder previously moved Matras to correct position*/
1868 for (i = s->start; i < s->base; i++)
1870 if (lexical(pwChar[i]) == lex_Matra_pre)
1872 int j;
1873 int g_start = g->start + i - s->start;
1874 if (g_start < g->base -1 )
1876 WCHAR og = glyphs[g_start];
1877 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1878 for (j = g_start; j < g->base-1; j++)
1879 glyphs[j] = glyphs[j+1];
1880 glyphs[g->base-1] = og;
1886 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1888 if (s->pref >= 0 && g->pref > g->base)
1890 int j;
1891 WCHAR og = glyphs[g->pref];
1892 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1893 for (j = g->pref; j > g->base; j--)
1894 glyphs[j] = glyphs[j-1];
1895 glyphs[g->base] = og;
1899 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1901 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1902 if (s->start == s->base && s->base == s->end) return;
1903 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1905 Reorder_Ra_follows_base(pwChar, s, lexical);
1906 Reorder_Matra_precede_base(pwChar, s, lexical);
1909 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1911 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1912 if (s->start == s->base && s->base == s->end) return;
1913 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1915 Reorder_Ra_follows_matra(pwChar, s, lexical);
1916 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1919 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1921 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1922 if (s->start == s->base && s->base == s->end) return;
1923 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1925 Reorder_Ra_follows_base(pwChar, s, lexical);
1926 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1929 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1931 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1932 if (s->start == s->base && s->base == s->end) return;
1933 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1935 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1936 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1939 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1941 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1942 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1943 if (s->start == s->base && s->base == s->end) return;
1944 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1946 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1949 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1951 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1952 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1953 if (s->start == s->base && s->base == s->end) return;
1954 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1956 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1957 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1961 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1963 if (shift == 0)
1964 return;
1966 if (glyph_index->start > index)
1967 glyph_index->start += shift;
1968 if (glyph_index->base > index)
1969 glyph_index->base+= shift;
1970 if (glyph_index->end > index)
1971 glyph_index->end+= shift;
1972 if (glyph_index->ralf > index)
1973 glyph_index->ralf+= shift;
1974 if (glyph_index->blwf > index)
1975 glyph_index->blwf+= shift;
1976 if (glyph_index->pref > index)
1977 glyph_index->pref+= shift;
1980 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 )
1982 int index = glyph_index->start;
1984 if (!feature)
1985 return;
1987 while(index <= glyph_index->end)
1989 INT nextIndex;
1990 INT prevCount = *pcGlyphs;
1991 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1992 if (nextIndex > GSUB_E_NOGLYPH)
1994 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1995 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1996 index = nextIndex;
1998 else
1999 index++;
2003 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2005 int i = 0;
2006 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)))))
2007 i++;
2008 if (index + i <= end-1)
2009 return index + i;
2010 else
2011 return -1;
2014 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)
2016 INT index, nextIndex;
2017 INT count,g_offset;
2019 count = syllable->base - syllable->start;
2021 g_offset = 0;
2022 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2023 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2025 INT prevCount = *pcGlyphs;
2026 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2027 if (nextIndex > GSUB_E_NOGLYPH)
2029 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2030 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2031 g_offset += (*pcGlyphs - prevCount);
2034 index+=2;
2035 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2039 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)
2041 INT nextIndex;
2042 INT prevCount = *pcGlyphs;
2044 if (syllable->ralf >= 0)
2046 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2047 if (nextIndex > GSUB_E_NOGLYPH)
2049 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2050 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2055 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2057 int i = 0;
2058 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2059 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2060 is_consonant(lexical(pwChars[index+i+1])))))
2061 i++;
2062 if (index + i <= end-1)
2063 return index+i;
2064 else
2065 return -1;
2068 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)
2070 INT index, nextIndex;
2071 INT count, g_offset=0;
2072 INT ralf = syllable->ralf;
2074 count = syllable->end - syllable->base;
2076 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2078 while (index >= 0)
2080 INT prevCount = *pcGlyphs;
2081 if (ralf >=0 && ralf < index)
2083 g_offset--;
2084 ralf = -1;
2087 if (!modern)
2089 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2090 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2091 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2094 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2095 if (nextIndex > GSUB_E_NOGLYPH)
2097 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2098 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2099 g_offset += (*pcGlyphs - prevCount);
2101 else if (!modern)
2103 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2104 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2105 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2108 index+=2;
2109 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2113 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)
2115 int c;
2116 int overall_shift = 0;
2117 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2118 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2119 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2120 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2121 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2122 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2123 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2124 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2125 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2126 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2127 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2128 IndicSyllable glyph_indexs;
2130 for (c = 0; c < syllable_count; c++)
2132 int old_end;
2133 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2134 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2135 old_end = glyph_indexs.end;
2137 if (locl)
2139 TRACE("applying feature locl\n");
2140 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2142 if (nukt)
2144 TRACE("applying feature nukt\n");
2145 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2147 if (akhn)
2149 TRACE("applying feature akhn\n");
2150 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2153 if (rphf)
2154 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2155 if (rkrf)
2157 TRACE("applying feature rkrf\n");
2158 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2160 if (pref)
2161 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2162 if (blwf)
2164 if (!modern)
2165 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2167 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2170 if (half)
2171 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2172 if (pstf)
2174 TRACE("applying feature pstf\n");
2175 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2177 if (vatu)
2179 TRACE("applying feature vatu\n");
2180 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2182 if (cjct)
2184 TRACE("applying feature cjct\n");
2185 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2188 if (second_reorder)
2189 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2191 overall_shift += glyph_indexs.end - old_end;
2195 static inline int unicode_lex(WCHAR c)
2197 int type;
2199 if (!c) return lex_Generic;
2200 if (c == 0x200D) return lex_ZWJ;
2201 if (c == 0x200C) return lex_ZWNJ;
2202 if (c == 0x00A0) return lex_NBSP;
2204 type = get_table_entry( indic_syllabic_table, c );
2206 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2208 switch( type )
2210 case 0x0d07: /* Unknown */
2211 case 0x0e07: /* Unknown */
2212 default: return lex_Generic;
2213 case 0x0001:
2214 case 0x0002:
2215 case 0x0011:
2216 case 0x0012:
2217 case 0x0013:
2218 case 0x0014: return lex_Modifier;
2219 case 0x0003:
2220 case 0x0009:
2221 case 0x000a:
2222 case 0x000b:
2223 case 0x000d:
2224 case 0x000e:
2225 case 0x000f:
2226 case 0x0010: return lex_Consonant;
2227 case 0x0004: return lex_Nukta;
2228 case 0x0005: return lex_Halant;
2229 case 0x0006:
2230 case 0x0008: return lex_Vowel;
2231 case 0x0007:
2232 case 0x0107: return lex_Matra_post;
2233 case 0x0207:
2234 case 0x0307: return lex_Matra_pre;
2235 case 0x0807:
2236 case 0x0907:
2237 case 0x0a07:
2238 case 0x0b07:
2239 case 0x0c07:
2240 case 0x0407: return lex_Composed_Vowel;
2241 case 0x0507: return lex_Matra_above;
2242 case 0x0607: return lex_Matra_below;
2243 case 0x000c:
2244 case 0x0015: return lex_Ra;
2248 static int sinhala_lex(WCHAR c)
2250 switch (c)
2252 case 0x0DDA:
2253 case 0x0DDD:
2254 case 0x0DDC:
2255 case 0x0DDE: return lex_Matra_post;
2256 default:
2257 return unicode_lex(c);
2261 static const VowelComponents Sinhala_vowels[] = {
2262 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2263 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2264 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2265 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2266 {0x0000, {0x0000,0x0000,0x0}}};
2268 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2270 int cCount = cChars;
2271 int i;
2272 WCHAR *input;
2273 IndicSyllable *syllables = NULL;
2274 int syllable_count = 0;
2276 if (*pcGlyphs != cChars)
2278 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2279 return;
2282 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2284 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2286 /* Step 1: Decompose multi part vowels */
2287 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2289 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2291 /* Step 2: Reorder within Syllables */
2292 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2293 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2295 /* Step 3: Strip dangling joiners */
2296 for (i = 0; i < cCount; i++)
2298 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2299 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2300 input[i] = 0x0020;
2303 /* Step 4: Base Form application to syllables */
2304 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2305 *pcGlyphs = cCount;
2306 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2308 HeapFree(GetProcessHeap(),0,input);
2309 HeapFree(GetProcessHeap(),0,syllables);
2312 static int devanagari_lex(WCHAR c)
2314 switch (c)
2316 case 0x0930: return lex_Ra;
2317 default:
2318 return unicode_lex(c);
2322 static const ConsonantComponents Devanagari_consonants[] ={
2323 {{0x0928, 0x093C, 0x00000}, 0x0929},
2324 {{0x0930, 0x093C, 0x00000}, 0x0931},
2325 {{0x0933, 0x093C, 0x00000}, 0x0934},
2326 {{0x0915, 0x093C, 0x00000}, 0x0958},
2327 {{0x0916, 0x093C, 0x00000}, 0x0959},
2328 {{0x0917, 0x093C, 0x00000}, 0x095A},
2329 {{0x091C, 0x093C, 0x00000}, 0x095B},
2330 {{0x0921, 0x093C, 0x00000}, 0x095C},
2331 {{0x0922, 0x093C, 0x00000}, 0x095D},
2332 {{0x092B, 0x093C, 0x00000}, 0x095E},
2333 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2335 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2337 int cCount = cChars;
2338 WCHAR *input;
2339 IndicSyllable *syllables = NULL;
2340 int syllable_count = 0;
2341 BOOL modern = get_GSUB_Indic2(psa, psc);
2343 if (*pcGlyphs != cChars)
2345 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2346 return;
2349 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2350 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2352 /* Step 1: Compose Consonant and Nukta */
2353 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2354 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2356 /* Step 2: Reorder within Syllables */
2357 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2358 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2359 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2360 *pcGlyphs = cCount;
2362 /* Step 3: Base Form application to syllables */
2363 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2365 HeapFree(GetProcessHeap(),0,input);
2366 HeapFree(GetProcessHeap(),0,syllables);
2369 static int bengali_lex(WCHAR c)
2371 switch (c)
2373 case 0x09B0: return lex_Ra;
2374 default:
2375 return unicode_lex(c);
2379 static const VowelComponents Bengali_vowels[] = {
2380 {0x09CB, {0x09C7,0x09BE,0x0000}},
2381 {0x09CC, {0x09C7,0x09D7,0x0000}},
2382 {0x0000, {0x0000,0x0000,0x0000}}};
2384 static const ConsonantComponents Bengali_consonants[] = {
2385 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2386 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2387 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2388 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2389 {{0x0000,0x0000,0x0000}, 0x0000}};
2391 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2393 int cCount = cChars;
2394 WCHAR *input;
2395 IndicSyllable *syllables = NULL;
2396 int syllable_count = 0;
2397 BOOL modern = get_GSUB_Indic2(psa, psc);
2399 if (*pcGlyphs != cChars)
2401 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2402 return;
2405 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2406 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2408 /* Step 1: Decompose Vowels and Compose Consonants */
2409 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2410 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2411 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2413 /* Step 2: Reorder within Syllables */
2414 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2415 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2416 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2417 *pcGlyphs = cCount;
2419 /* Step 3: Initial form is only applied to the beginning of words */
2420 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2422 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2424 int index = cCount;
2425 int gCount = 1;
2426 if (index > 0) index++;
2428 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2432 /* Step 4: Base Form application to syllables */
2433 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2435 HeapFree(GetProcessHeap(),0,input);
2436 HeapFree(GetProcessHeap(),0,syllables);
2439 static int gurmukhi_lex(WCHAR c)
2441 if (c == 0x0A71)
2442 return lex_Modifier;
2443 else
2444 return unicode_lex(c);
2447 static const ConsonantComponents Gurmukhi_consonants[] = {
2448 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2449 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2450 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2451 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2452 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2453 {{0x0000,0x0000,0x0000}, 0x0000}};
2455 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2457 int cCount = cChars;
2458 WCHAR *input;
2459 IndicSyllable *syllables = NULL;
2460 int syllable_count = 0;
2461 BOOL modern = get_GSUB_Indic2(psa, psc);
2463 if (*pcGlyphs != cChars)
2465 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2466 return;
2469 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2470 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2472 /* Step 1: Compose Consonants */
2473 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2474 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2476 /* Step 2: Reorder within Syllables */
2477 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2478 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2479 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2480 *pcGlyphs = cCount;
2482 /* Step 3: Base Form application to syllables */
2483 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2485 HeapFree(GetProcessHeap(),0,input);
2486 HeapFree(GetProcessHeap(),0,syllables);
2489 static int gujarati_lex(WCHAR c)
2491 switch (c)
2493 case 0x0AB0: return lex_Ra;
2494 default:
2495 return unicode_lex(c);
2499 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2501 int cCount = cChars;
2502 WCHAR *input;
2503 IndicSyllable *syllables = NULL;
2504 int syllable_count = 0;
2505 BOOL modern = get_GSUB_Indic2(psa, psc);
2507 if (*pcGlyphs != cChars)
2509 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2510 return;
2513 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2514 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2516 /* Step 1: Reorder within Syllables */
2517 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2518 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2519 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2520 *pcGlyphs = cCount;
2522 /* Step 2: Base Form application to syllables */
2523 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2525 HeapFree(GetProcessHeap(),0,input);
2526 HeapFree(GetProcessHeap(),0,syllables);
2529 static int oriya_lex(WCHAR c)
2531 switch (c)
2533 case 0x0B30: return lex_Ra;
2534 default:
2535 return unicode_lex(c);
2539 static const VowelComponents Oriya_vowels[] = {
2540 {0x0B48, {0x0B47,0x0B56,0x0000}},
2541 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2542 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2543 {0x0000, {0x0000,0x0000,0x0000}}};
2545 static const ConsonantComponents Oriya_consonants[] = {
2546 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2547 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2548 {{0x0000,0x0000,0x0000}, 0x0000}};
2550 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2552 int cCount = cChars;
2553 WCHAR *input;
2554 IndicSyllable *syllables = NULL;
2555 int syllable_count = 0;
2556 BOOL modern = get_GSUB_Indic2(psa, psc);
2558 if (*pcGlyphs != cChars)
2560 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2561 return;
2564 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2565 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2567 /* Step 1: Decompose Vowels and Compose Consonants */
2568 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2569 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2570 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2572 /* Step 2: Reorder within Syllables */
2573 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2574 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2575 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2576 *pcGlyphs = cCount;
2578 /* Step 3: Base Form application to syllables */
2579 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2581 HeapFree(GetProcessHeap(),0,input);
2582 HeapFree(GetProcessHeap(),0,syllables);
2585 static int tamil_lex(WCHAR c)
2587 return unicode_lex(c);
2590 static const VowelComponents Tamil_vowels[] = {
2591 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2592 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2593 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2594 {0x0000, {0x0000,0x0000,0x0000}}};
2596 static const ConsonantComponents Tamil_consonants[] = {
2597 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2598 {{0x0000,0x0000,0x0000}, 0x0000}};
2600 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2602 int cCount = cChars;
2603 WCHAR *input;
2604 IndicSyllable *syllables = NULL;
2605 int syllable_count = 0;
2606 BOOL modern = get_GSUB_Indic2(psa, psc);
2608 if (*pcGlyphs != cChars)
2610 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2611 return;
2614 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2615 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2617 /* Step 1: Decompose Vowels and Compose Consonants */
2618 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2619 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2620 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2622 /* Step 2: Reorder within Syllables */
2623 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2624 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2625 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2626 *pcGlyphs = cCount;
2628 /* Step 3: Base Form application to syllables */
2629 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2631 HeapFree(GetProcessHeap(),0,input);
2632 HeapFree(GetProcessHeap(),0,syllables);
2635 static int telugu_lex(WCHAR c)
2637 switch (c)
2639 case 0x0C43:
2640 case 0x0C44: return lex_Modifier;
2641 default:
2642 return unicode_lex(c);
2646 static const VowelComponents Telugu_vowels[] = {
2647 {0x0C48, {0x0C46,0x0C56,0x0000}},
2648 {0x0000, {0x0000,0x0000,0x0000}}};
2650 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2652 int cCount = cChars;
2653 WCHAR *input;
2654 IndicSyllable *syllables = NULL;
2655 int syllable_count = 0;
2656 BOOL modern = get_GSUB_Indic2(psa, psc);
2658 if (*pcGlyphs != cChars)
2660 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2661 return;
2664 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2665 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2667 /* Step 1: Decompose Vowels */
2668 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2669 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2671 /* Step 2: Reorder within Syllables */
2672 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2673 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2674 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2675 *pcGlyphs = cCount;
2677 /* Step 3: Base Form application to syllables */
2678 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2680 HeapFree(GetProcessHeap(),0,input);
2681 HeapFree(GetProcessHeap(),0,syllables);
2684 static int kannada_lex(WCHAR c)
2686 switch (c)
2688 case 0x0CB0: return lex_Ra;
2689 default:
2690 return unicode_lex(c);
2694 static const VowelComponents Kannada_vowels[] = {
2695 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2696 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2697 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2698 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2699 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2700 {0x0000, {0x0000,0x0000,0x0000}}};
2702 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2704 int cCount = cChars;
2705 WCHAR *input;
2706 IndicSyllable *syllables = NULL;
2707 int syllable_count = 0;
2708 BOOL modern = get_GSUB_Indic2(psa, psc);
2710 if (*pcGlyphs != cChars)
2712 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2713 return;
2716 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2717 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2719 /* Step 1: Decompose Vowels */
2720 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2721 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2723 /* Step 2: Reorder within Syllables */
2724 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2725 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2726 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2727 *pcGlyphs = cCount;
2729 /* Step 3: Base Form application to syllables */
2730 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2732 HeapFree(GetProcessHeap(),0,input);
2733 HeapFree(GetProcessHeap(),0,syllables);
2736 static int malayalam_lex(WCHAR c)
2738 return unicode_lex(c);
2741 static const VowelComponents Malayalam_vowels[] = {
2742 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2743 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2744 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2745 {0x0000, {0x0000,0x0000,0x0000}}};
2747 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2749 int cCount = cChars;
2750 WCHAR *input;
2751 IndicSyllable *syllables = NULL;
2752 int syllable_count = 0;
2753 BOOL modern = get_GSUB_Indic2(psa, psc);
2755 if (*pcGlyphs != cChars)
2757 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2758 return;
2761 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2762 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2764 /* Step 1: Decompose Vowels */
2765 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2766 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2768 /* Step 2: Reorder within Syllables */
2769 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2770 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2771 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2772 *pcGlyphs = cCount;
2774 /* Step 3: Base Form application to syllables */
2775 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2777 HeapFree(GetProcessHeap(),0,input);
2778 HeapFree(GetProcessHeap(),0,syllables);
2781 static int khmer_lex(WCHAR c)
2783 return unicode_lex(c);
2786 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2788 int cCount = cChars;
2789 WCHAR *input;
2790 IndicSyllable *syllables = NULL;
2791 int syllable_count = 0;
2793 if (*pcGlyphs != cChars)
2795 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2796 return;
2799 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2800 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2802 /* Step 1: Reorder within Syllables */
2803 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2804 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2805 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2806 *pcGlyphs = cCount;
2808 /* Step 2: Base Form application to syllables */
2809 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2811 HeapFree(GetProcessHeap(),0,input);
2812 HeapFree(GetProcessHeap(),0,syllables);
2815 static inline BOOL mongolian_wordbreak(WCHAR chr)
2817 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2820 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2822 INT *context_shape;
2823 INT dirL;
2824 int i;
2825 int char_index;
2826 int glyph_index;
2828 if (*pcGlyphs != cChars)
2830 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2831 return;
2834 if (!psa->fLogicalOrder && psa->fRTL)
2835 dirL = -1;
2836 else
2837 dirL = 1;
2839 if (!psc->GSUB_Table)
2840 return;
2842 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2844 for (i = 0; i < cChars; i++)
2846 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2848 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2849 context_shape[i] = Xn;
2850 else
2851 context_shape[i] = Xl;
2853 else
2855 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2856 context_shape[i] = Xr;
2857 else
2858 context_shape[i] = Xm;
2862 /* Contextual Shaping */
2863 if (dirL > 0)
2864 char_index = glyph_index = 0;
2865 else
2866 char_index = glyph_index = cChars-1;
2868 while(char_index < cChars && char_index >= 0)
2870 INT nextIndex;
2871 INT prevCount = *pcGlyphs;
2872 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2874 if (nextIndex > GSUB_E_NOGLYPH)
2876 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2877 glyph_index = nextIndex;
2878 char_index += dirL;
2880 else
2882 char_index += dirL;
2883 glyph_index += dirL;
2887 HeapFree(GetProcessHeap(),0,context_shape);
2890 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)
2892 int i,k;
2894 for (i = 0; i < cGlyphs; i++)
2896 int char_index[20];
2897 int char_count = 0;
2899 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2900 if (k>=0)
2902 for (; k < cChars && pwLogClust[k] == i; k++)
2903 char_index[char_count++] = k;
2906 if (char_count == 0)
2907 continue;
2909 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2911 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2912 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2914 else
2915 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2918 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2919 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2922 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2924 int i;
2926 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2928 for (i = 0; i < cGlyphs; i++)
2929 if (pGlyphProp[i].sva.fZeroWidth)
2930 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2933 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2935 int i;
2936 for (i = 0; i < cGlyphs; i++)
2938 pGlyphProp[i].sva.fClusterStart = 1;
2939 pGlyphProp[i].sva.fDiacritic = 0;
2940 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2942 if (pwGlyphs[i] == psc->sfp.wgDefault)
2943 pGlyphProp[i].sva.fZeroWidth = 0;
2944 else
2945 pGlyphProp[i].sva.fZeroWidth = 1;
2949 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 )
2951 int i,k;
2952 int initGlyph, finaGlyph;
2953 INT dirR, dirL;
2954 BYTE *spaces;
2956 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2957 memset(spaces,0,cGlyphs);
2959 if (!psa->fLogicalOrder && psa->fRTL)
2961 initGlyph = cGlyphs-1;
2962 finaGlyph = 0;
2963 dirR = 1;
2964 dirL = -1;
2966 else
2968 initGlyph = 0;
2969 finaGlyph = cGlyphs-1;
2970 dirR = -1;
2971 dirL = 1;
2974 for (i = 0; i < cGlyphs; i++)
2976 for (k = 0; k < cChars; k++)
2977 if (pwLogClust[k] == i)
2979 if (pwcChars[k] == 0x0020)
2980 spaces[i] = 1;
2984 for (i = 0; i < cGlyphs; i++)
2986 int char_index[20];
2987 int char_count = 0;
2988 BOOL isInit, isFinal;
2990 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2991 if (k>=0)
2993 for (; k < cChars && pwLogClust[k] == i; k++)
2994 char_index[char_count++] = k;
2997 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2998 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3000 if (char_count == 0)
3001 continue;
3003 if (char_count == 1)
3005 if (pwcChars[char_index[0]] == 0x0020) /* space */
3007 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3008 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3010 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3011 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3012 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3014 if (!isInit && !isFinal)
3015 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3016 else if (isInit)
3017 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3018 else
3019 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3021 else if (!isInit)
3023 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3024 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3025 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3026 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3027 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3029 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3030 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3031 else
3032 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3034 else if (!isInit && !isFinal)
3035 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3036 else
3037 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3039 else if (char_count == 2)
3041 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3042 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3043 else if (!isInit)
3044 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3045 else
3046 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3048 else if (!isInit && !isFinal)
3049 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3050 else
3051 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3054 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3055 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3056 HeapFree(GetProcessHeap(),0,spaces);
3059 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 )
3061 int i,k;
3063 for (i = 0; i < cGlyphs; i++)
3065 int char_index[20];
3066 int char_count = 0;
3068 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3069 if (k>=0)
3071 for (; k < cChars && pwLogClust[k] == i; k++)
3072 char_index[char_count++] = k;
3075 if (char_count == 0)
3076 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3077 else
3079 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3080 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3081 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3085 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3086 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3089 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 )
3091 int i;
3092 int finaGlyph;
3093 INT dirL;
3095 if (!psa->fLogicalOrder && psa->fRTL)
3097 finaGlyph = 0;
3098 dirL = -1;
3100 else
3102 finaGlyph = cGlyphs-1;
3103 dirL = 1;
3106 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3108 for (i = 0; i < cGlyphs; i++)
3110 int k;
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 (i == finaGlyph)
3122 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3123 else
3124 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3126 if (char_count == 0)
3127 continue;
3129 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3130 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3132 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3133 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3134 pGlyphProp[i].sva.fClusterStart = 0;
3137 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3139 /* Do not allow justification between marks and their base */
3140 for (i = 0; i < cGlyphs; i++)
3142 if (!pGlyphProp[i].sva.fClusterStart)
3143 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3147 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)
3149 int i,k;
3151 for (i = 0; i < cGlyphs; i++)
3153 int char_index[20];
3154 int char_count = 0;
3156 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3157 if (k>=0)
3159 for (; k < cChars && pwLogClust[k] == i; k++)
3160 char_index[char_count++] = k;
3163 if (char_count == 0)
3164 continue;
3166 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3168 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3169 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3171 else
3172 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3174 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3175 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3178 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)
3180 int i,k;
3182 for (i = 0; i < cGlyphs; i++)
3184 int char_index[20];
3185 int char_count = 0;
3187 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3188 if (k>=0)
3190 for (; k < cChars && pwLogClust[k] == i; k++)
3191 char_index[char_count++] = k;
3194 if (char_count == 0)
3195 continue;
3197 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3199 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3200 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3202 else
3203 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3205 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3206 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3208 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3209 for (i = 0; i < cGlyphs; i++)
3211 if (!pGlyphProp[i].sva.fClusterStart)
3213 pGlyphProp[i].sva.fDiacritic = 0;
3214 pGlyphProp[i].sva.fZeroWidth = 0;
3219 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)
3221 int i,k;
3223 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3224 for (i = 0; i < cGlyphs; i++)
3226 int char_index[20];
3227 int char_count = 0;
3229 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3230 if (k>=0)
3232 for (; k < cChars && pwLogClust[k] == i; k++)
3233 char_index[char_count++] = k;
3236 if (override_gsub)
3238 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3239 pGlyphProp[i].sva.fDiacritic = FALSE;
3240 pGlyphProp[i].sva.fZeroWidth = FALSE;
3243 if (char_count == 0)
3245 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3246 continue;
3249 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3251 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3252 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3254 else
3255 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3257 pGlyphProp[i].sva.fClusterStart = 0;
3258 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3259 switch (lexical(pwcChars[char_index[k]]))
3261 case lex_Matra_pre:
3262 case lex_Matra_post:
3263 case lex_Matra_above:
3264 case lex_Matra_below:
3265 case lex_Modifier:
3266 case lex_Halant:
3267 break;
3268 case lex_ZWJ:
3269 case lex_ZWNJ:
3270 /* check for dangling joiners */
3271 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3272 pGlyphProp[i].sva.fClusterStart = 1;
3273 else
3274 k = char_count;
3275 break;
3276 default:
3277 pGlyphProp[i].sva.fClusterStart = 1;
3278 break;
3282 if (use_syllables)
3284 IndicSyllable *syllables = NULL;
3285 int syllable_count = 0;
3286 BOOL modern = get_GSUB_Indic2(psa, psc);
3288 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3290 for (i = 0; i < syllable_count; i++)
3292 int j;
3293 WORD g = pwLogClust[syllables[i].start];
3294 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3296 if (pwLogClust[j] != g)
3298 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3299 pwLogClust[j] = g;
3304 HeapFree(GetProcessHeap(), 0, syllables);
3307 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3310 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 )
3312 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3315 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 )
3317 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3320 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 )
3322 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3325 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 )
3327 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3330 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 )
3332 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3335 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 )
3337 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3340 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 )
3342 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3345 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 )
3347 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3350 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 )
3352 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3355 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 )
3357 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3360 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 )
3362 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3365 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)
3367 load_ot_tables(hdc, psc);
3369 if (ShapingData[psa->eScript].charGlyphPropProc)
3370 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3371 else
3372 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3375 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3377 load_ot_tables(hdc, psc);
3379 if (ShapingData[psa->eScript].contextProc)
3380 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3383 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)
3385 int i;
3386 INT dirL;
3388 if (!rpRangeProperties)
3389 return;
3391 load_ot_tables(hdc, psc);
3393 if (!psc->GSUB_Table)
3394 return;
3396 if (!psa->fLogicalOrder && psa->fRTL)
3397 dirL = -1;
3398 else
3399 dirL = 1;
3401 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3403 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3404 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3408 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3410 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3411 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3413 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3416 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3418 const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3419 int i;
3421 load_ot_tables(hdc, psc);
3423 if (!psc->GPOS_Table || !psc->otm)
3424 return;
3426 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3428 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3430 LoadedFeature *feature;
3432 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3433 if (!feature)
3434 continue;
3436 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3441 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3443 LoadedFeature *feature;
3444 int i;
3446 if (!ShapingData[psa->eScript].requiredFeatures)
3447 return S_OK;
3449 load_ot_tables(hdc, psc);
3451 /* we need to have at least one of the required features */
3452 i = 0;
3453 while (ShapingData[psa->eScript].requiredFeatures[i])
3455 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3456 if (feature)
3457 return S_OK;
3458 i++;
3461 return USP_E_SCRIPT_NOT_IN_FONT;
3464 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3465 SCRIPT_ANALYSIS *psa, int cMaxTags,
3466 OPENTYPE_TAG *pScriptTags, int *pcTags)
3468 HRESULT hr;
3469 OPENTYPE_TAG searching = 0x00000000;
3471 load_ot_tables(hdc, psc);
3473 if (psa && scriptInformation[psa->eScript].scriptTag)
3474 searching = scriptInformation[psa->eScript].scriptTag;
3476 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3477 if (FAILED(hr))
3478 *pcTags = 0;
3479 return hr;
3482 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3483 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3484 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3485 int *pcTags)
3487 HRESULT hr;
3488 OPENTYPE_TAG searching = 0x00000000;
3489 BOOL fellback = FALSE;
3491 load_ot_tables(hdc, psc);
3493 if (psa && psc->userLang != 0)
3494 searching = psc->userLang;
3496 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3497 if (FAILED(hr))
3499 fellback = TRUE;
3500 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3503 if (FAILED(hr) || fellback)
3504 *pcTags = 0;
3505 if (SUCCEEDED(hr) && fellback && psa)
3506 hr = E_INVALIDARG;
3507 return hr;
3510 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3511 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3512 OPENTYPE_TAG tagLangSys, int cMaxTags,
3513 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3515 HRESULT hr;
3516 BOOL filter = FALSE;
3518 load_ot_tables(hdc, psc);
3520 if (psa && scriptInformation[psa->eScript].scriptTag)
3522 FIXME("Filtering not implemented\n");
3523 filter = TRUE;
3526 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3528 if (FAILED(hr))
3529 *pcTags = 0;
3530 return hr;