mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / gdi32 / uniscribe / shape.c
blob843d670f1e9f1b3ad722c2b488f86a5a0e306992
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
39 #define FIRST_ARABIC_CHAR 0x0600
40 #define LAST_ARABIC_CHAR 0x06ff
42 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
43 WCHAR*, INT, WORD*, INT*, INT, WORD*);
45 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
63 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
64 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
66 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
68 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
69 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
73 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
75 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
76 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
77 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
78 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
79 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
80 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
81 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
82 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
83 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
84 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
85 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
86 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
88 extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
89 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
90 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
92 enum joining_types
94 jtU = 0,
95 jtL = 1,
96 jtR = 2,
97 jtD = 3,
98 jtC = jtD,
99 jgALAPH = 4,
100 jgDALATH_RISH = 5,
101 jtT = 6,
104 enum joined_forms {
105 Xn=0,
109 /* Syriac Alaph */
110 Afj,
111 Afn,
115 typedef struct tagVowelComponents
117 WCHAR base;
118 WCHAR parts[3];
119 } VowelComponents;
121 typedef struct tagConsonantComponents
123 WCHAR parts[3];
124 WCHAR output;
125 } ConsonantComponents;
127 typedef void (*second_reorder_function)(const WCHAR *chars, const IndicSyllable *syllable,
128 WORD *glyphs, const IndicSyllable *glyph_index, lexical_function lex);
130 typedef int (*combining_lexical_function)(WCHAR c);
132 /* the orders of joined_forms and contextual_features need to line up */
133 static const char *const contextual_features[] =
135 "isol",
136 "fina",
137 "init",
138 "medi",
139 /* Syriac Alaph */
140 "med2",
141 "fin2",
142 "fin3"
145 static OPENTYPE_FEATURE_RECORD standard_features[] =
147 { MS_MAKE_TAG('c','c','m','p'), 1},
148 { MS_MAKE_TAG('l','o','c','l'), 1},
151 static OPENTYPE_FEATURE_RECORD latin_features[] =
153 { MS_MAKE_TAG('l','o','c','l'), 1},
154 { MS_MAKE_TAG('c','c','m','p'), 1},
155 { MS_MAKE_TAG('l','i','g','a'), 1},
156 { MS_MAKE_TAG('c','l','i','g'), 1},
159 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
161 { MS_MAKE_TAG('k','e','r','n'), 1},
162 { MS_MAKE_TAG('m','a','r','k'), 1},
163 { MS_MAKE_TAG('m','k','m','k'), 1},
166 static OPENTYPE_FEATURE_RECORD arabic_features[] =
168 { MS_MAKE_TAG('r','l','i','g'), 1},
169 { MS_MAKE_TAG('c','a','l','t'), 1},
170 { MS_MAKE_TAG('l','i','g','a'), 1},
171 { MS_MAKE_TAG('d','l','i','g'), 1},
172 { MS_MAKE_TAG('c','s','w','h'), 1},
173 { MS_MAKE_TAG('m','s','e','t'), 1},
176 static const char *const required_arabic_features[] =
178 "fina",
179 "init",
180 "medi",
181 "rlig",
182 NULL
185 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
187 { MS_MAKE_TAG('c','u','r','s'), 1},
188 { MS_MAKE_TAG('k','e','r','n'), 1},
189 { MS_MAKE_TAG('m','a','r','k'), 1},
190 { MS_MAKE_TAG('m','k','m','k'), 1},
193 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
195 { MS_MAKE_TAG('c','c','m','p'), 1},
196 { MS_MAKE_TAG('d','l','i','g'), 0},
199 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
201 { MS_MAKE_TAG('k','e','r','n'), 1},
202 { MS_MAKE_TAG('m','a','r','k'), 1},
205 static OPENTYPE_FEATURE_RECORD syriac_features[] =
207 { MS_MAKE_TAG('r','l','i','g'), 1},
208 { MS_MAKE_TAG('c','a','l','t'), 1},
209 { MS_MAKE_TAG('l','i','g','a'), 1},
210 { MS_MAKE_TAG('d','l','i','g'), 1},
213 static const char *const required_syriac_features[] =
215 "fina",
216 "fin2",
217 "fin3",
218 "init",
219 "medi",
220 "med2",
221 "rlig",
222 NULL
225 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
227 { MS_MAKE_TAG('k','e','r','n'), 1},
228 { MS_MAKE_TAG('m','a','r','k'), 1},
229 { MS_MAKE_TAG('m','k','m','k'), 1},
232 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
234 /* Presentation forms */
235 { MS_MAKE_TAG('b','l','w','s'), 1},
236 { MS_MAKE_TAG('a','b','v','s'), 1},
237 { MS_MAKE_TAG('p','s','t','s'), 1},
240 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
242 { MS_MAKE_TAG('a','b','v','s'), 1},
243 { MS_MAKE_TAG('b','l','w','s'), 1},
246 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
248 { MS_MAKE_TAG('a','b','v','m'), 1},
249 { MS_MAKE_TAG('b','l','w','m'), 1},
252 static OPENTYPE_FEATURE_RECORD phags_features[] =
254 { MS_MAKE_TAG('a','b','v','s'), 1},
255 { MS_MAKE_TAG('b','l','w','s'), 1},
256 { MS_MAKE_TAG('c','a','l','t'), 1},
259 static OPENTYPE_FEATURE_RECORD thai_features[] =
261 { MS_MAKE_TAG('c','c','m','p'), 1},
264 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
266 { MS_MAKE_TAG('k','e','r','n'), 1},
267 { MS_MAKE_TAG('m','a','r','k'), 1},
268 { MS_MAKE_TAG('m','k','m','k'), 1},
271 static const char *const required_lao_features[] =
273 "ccmp",
274 NULL
277 static const char *const required_devanagari_features[] =
279 "nukt",
280 "akhn",
281 "rphf",
282 "blwf",
283 "half",
284 "vatu",
285 "pres",
286 "abvs",
287 "blws",
288 "psts",
289 "haln",
290 NULL
293 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
295 { MS_MAKE_TAG('p','r','e','s'), 1},
296 { MS_MAKE_TAG('a','b','v','s'), 1},
297 { MS_MAKE_TAG('b','l','w','s'), 1},
298 { MS_MAKE_TAG('p','s','t','s'), 1},
299 { MS_MAKE_TAG('h','a','l','n'), 1},
300 { MS_MAKE_TAG('c','a','l','t'), 1},
303 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
305 { MS_MAKE_TAG('k','e','r','n'), 1},
306 { MS_MAKE_TAG('d','i','s','t'), 1},
307 { MS_MAKE_TAG('a','b','v','m'), 1},
308 { MS_MAKE_TAG('b','l','w','m'), 1},
311 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
313 { MS_MAKE_TAG('l','i','g','a'), 1},
314 { MS_MAKE_TAG('c','l','i','g'), 1},
317 static const char *const required_bengali_features[] =
319 "nukt",
320 "akhn",
321 "rphf",
322 "blwf",
323 "half",
324 "vatu",
325 "pstf",
326 "init",
327 "abvs",
328 "blws",
329 "psts",
330 "haln",
331 NULL
334 static const char *const required_gurmukhi_features[] =
336 "nukt",
337 "akhn",
338 "rphf",
339 "blwf",
340 "half",
341 "pstf",
342 "vatu",
343 "cjct",
344 "pres",
345 "abvs",
346 "blws",
347 "psts",
348 "haln",
349 "calt",
350 NULL
353 static const char *const required_oriya_features[] =
355 "nukt",
356 "akhn",
357 "rphf",
358 "blwf",
359 "pstf",
360 "cjct",
361 "pres",
362 "abvs",
363 "blws",
364 "psts",
365 "haln",
366 "calt",
367 NULL
370 static const char *const required_tamil_features[] =
372 "nukt",
373 "akhn",
374 "rphf",
375 "pref",
376 "half",
377 "pres",
378 "abvs",
379 "blws",
380 "psts",
381 "haln",
382 "calt",
383 NULL
386 static const char *const required_telugu_features[] =
388 "nukt",
389 "akhn",
390 "rphf",
391 "pref",
392 "half",
393 "pstf",
394 "cjct",
395 "pres",
396 "abvs",
397 "blws",
398 "psts",
399 "haln",
400 "calt",
401 NULL
404 static OPENTYPE_FEATURE_RECORD khmer_features[] =
406 { MS_MAKE_TAG('p','r','e','s'), 1},
407 { MS_MAKE_TAG('b','l','w','s'), 1},
408 { MS_MAKE_TAG('a','b','v','s'), 1},
409 { MS_MAKE_TAG('p','s','t','s'), 1},
410 { MS_MAKE_TAG('c','l','i','g'), 1},
413 static const char *const required_khmer_features[] =
415 "pref",
416 "blwf",
417 "abvf",
418 "pstf",
419 "pres",
420 "blws",
421 "abvs",
422 "psts",
423 "clig",
424 NULL
427 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
429 { MS_MAKE_TAG('d','i','s','t'), 1},
430 { MS_MAKE_TAG('b','l','w','m'), 1},
431 { MS_MAKE_TAG('a','b','v','m'), 1},
432 { MS_MAKE_TAG('m','k','m','k'), 1},
435 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
437 { MS_MAKE_TAG('c','c','m','p'), 1},
438 { MS_MAKE_TAG('l','o','c','l'), 1},
439 { MS_MAKE_TAG('c','a','l','t'), 1},
440 { MS_MAKE_TAG('l','i','g','a'), 1},
443 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
445 { MS_MAKE_TAG('c','c','m','p'), 1},
446 { MS_MAKE_TAG('l','o','c','l'), 1},
447 { MS_MAKE_TAG('c','a','l','t'), 1},
448 { MS_MAKE_TAG('r','l','i','g'), 1},
451 typedef struct ScriptShapeDataTag {
452 TEXTRANGE_PROPERTIES defaultTextRange;
453 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
454 const char *const *requiredFeatures;
455 OPENTYPE_TAG newOtTag;
456 ContextualShapingProc contextProc;
457 ShapeCharGlyphPropProc charGlyphPropProc;
458 } ScriptShapeData;
460 /* in order of scripts */
461 static const ScriptShapeData ShapingData[] =
463 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
464 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
465 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
466 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
467 {{ standard_features, 2}, {NULL, 0}, NULL, 0, ContextualShape_Control, ShapeCharGlyphProp_Control},
468 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
469 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
470 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
471 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
472 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
473 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
474 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
475 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
476 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
477 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
478 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
479 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
480 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
481 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
482 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
483 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
484 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
485 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
486 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
497 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
498 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
499 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
500 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
501 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
502 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
503 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
504 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
505 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
506 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
507 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
509 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
511 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
512 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
513 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
516 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
522 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
523 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
524 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
526 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
527 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
528 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
529 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
530 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
531 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
532 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
533 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
534 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
535 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
536 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
537 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
538 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
539 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
540 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
541 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
542 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
543 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
544 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
547 extern scriptData scriptInformation[];
549 static int GSUB_apply_feature_all_lookups(const void *header, LoadedFeature *feature,
550 WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count)
552 int i;
553 int out_index = GSUB_E_NOGLYPH;
555 TRACE("%i lookups\n", feature->lookup_count);
556 for (i = 0; i < feature->lookup_count; i++)
558 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
559 if (out_index != GSUB_E_NOGLYPH)
560 break;
562 if (out_index == GSUB_E_NOGLYPH)
563 TRACE("lookups found no glyphs\n");
564 else
566 int out2;
567 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
568 if (out2!=GSUB_E_NOGLYPH)
569 out_index = out2;
571 return out_index;
574 static OPENTYPE_TAG get_opentype_script(HDC hdc, const SCRIPT_ANALYSIS *psa,
575 const ScriptCache *script_cache, BOOL try_new)
577 UINT charset;
579 if (script_cache->userScript)
581 if (try_new && ShapingData[psa->eScript].newOtTag
582 && script_cache->userScript == scriptInformation[psa->eScript].scriptTag)
583 return ShapingData[psa->eScript].newOtTag;
585 return script_cache->userScript;
588 if (try_new && ShapingData[psa->eScript].newOtTag)
589 return ShapingData[psa->eScript].newOtTag;
591 if (scriptInformation[psa->eScript].scriptTag)
592 return scriptInformation[psa->eScript].scriptTag;
595 * fall back to the font charset
597 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
598 switch (charset)
600 case ANSI_CHARSET:
601 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
602 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
603 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
604 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
605 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
606 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
607 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
608 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
609 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
610 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
611 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
612 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
613 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
614 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
615 default: return MS_MAKE_TAG('l','a','t','n');
619 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
621 LoadedFeature *feature = NULL;
623 if (psc->GSUB_Table || psc->GPOS_Table)
625 int attempt = 2;
626 OPENTYPE_TAG tags;
627 OPENTYPE_TAG language;
628 OPENTYPE_TAG script = 0x00000000;
629 int cTags;
633 script = get_opentype_script(hdc,psa,psc,(attempt==2));
634 if (psc->userLang != 0)
635 language = psc->userLang;
636 else
637 language = MS_MAKE_TAG('d','f','l','t');
638 attempt--;
640 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
642 } while(attempt && !feature);
644 /* try in the default (latin) table */
645 if (!feature)
647 if (!script)
648 script = MS_MAKE_TAG('l','a','t','n');
649 OpenType_GetFontFeatureTags(psc, script, MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
653 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
654 return feature;
657 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)
659 LoadedFeature *feature;
661 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
662 if (!feature)
663 return GSUB_E_NOFEATURE;
665 TRACE("applying feature %s\n",feat);
666 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
669 static VOID *load_gsub_table(HDC hdc)
671 VOID* GSUB_Table = NULL;
672 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
673 if (length != GDI_ERROR)
675 GSUB_Table = heap_alloc(length);
676 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
677 TRACE("Loaded GSUB table of %i bytes\n",length);
679 return GSUB_Table;
682 static VOID *load_gpos_table(HDC hdc)
684 VOID* GPOS_Table = NULL;
685 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
686 if (length != GDI_ERROR)
688 GPOS_Table = heap_alloc(length);
689 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
690 TRACE("Loaded GPOS table of %i bytes\n",length);
692 return GPOS_Table;
695 static VOID *load_gdef_table(HDC hdc)
697 VOID* GDEF_Table = NULL;
698 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
699 if (length != GDI_ERROR)
701 GDEF_Table = heap_alloc(length);
702 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
703 TRACE("Loaded GDEF table of %i bytes\n",length);
705 return GDEF_Table;
708 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
710 if (!psc->GSUB_Table)
711 psc->GSUB_Table = load_gsub_table(hdc);
712 if (!psc->GPOS_Table)
713 psc->GPOS_Table = load_gpos_table(hdc);
714 if (!psc->GDEF_Table)
715 psc->GDEF_Table = load_gdef_table(hdc);
718 int SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc,
719 const WCHAR *chars, int write_dir, int count, const char *feature)
721 WORD *glyphs;
722 INT glyph_count = count;
723 INT rc;
725 glyphs = heap_calloc(count, 2 * sizeof(*glyphs));
726 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
727 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
728 if (rc > GSUB_E_NOGLYPH)
729 rc = count - glyph_count;
730 else
731 rc = 0;
733 heap_free(glyphs);
734 return rc;
737 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
739 int i;
741 for (i = 0; i < cGlyphs; i++)
743 if (!pGlyphProp[i].sva.fClusterStart)
745 int j;
746 for (j = 0; j < cChars; j++)
748 if (pwLogClust[j] == i)
750 int k = j;
751 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
752 k-=1;
753 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
754 pwLogClust[j] = pwLogClust[k];
761 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
763 if (changeCount == 0)
764 return;
765 else
767 int cluster_dir = pwLogClust[0] < pwLogClust[chars-1] ? 1 : -1;
768 int i;
769 int target_glyph = nextIndex - write_dir;
770 int target_index = -1;
771 int replacing_glyph = -1;
772 int changed = 0;
774 if (changeCount > 0)
776 if (write_dir > 0)
777 target_glyph = nextIndex - changeCount;
778 else
779 target_glyph = nextIndex + (changeCount + 1);
782 target_index = USP10_FindGlyphInLogClust(pwLogClust, chars, target_glyph);
783 if (target_index == -1)
785 ERR("Unable to find target glyph\n");
786 return;
789 if (changeCount < 0)
791 /* merge glyphs */
792 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
794 if (pwLogClust[i] == target_glyph)
795 continue;
796 if(pwLogClust[i] == replacing_glyph)
797 pwLogClust[i] = target_glyph;
798 else
800 changed--;
801 if (changed >= changeCount)
803 replacing_glyph = pwLogClust[i];
804 pwLogClust[i] = target_glyph;
806 else
807 break;
811 /* renumber trailing indices */
812 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
814 if (pwLogClust[i] != target_glyph)
815 pwLogClust[i] += changeCount;
818 else
820 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
821 pwLogClust[i] += changeCount;
826 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 )
828 if (psc->GSUB_Table)
830 LoadedFeature *feature;
831 int lookup_index;
833 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
834 if (!feature)
835 return GSUB_E_NOFEATURE;
837 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
838 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
840 int i;
842 if (write_dir > 0)
843 i = 0;
844 else
845 i = *pcGlyphs-1;
846 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
847 while(i < *pcGlyphs && i >= 0)
849 INT nextIndex;
850 INT prevCount = *pcGlyphs;
852 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
853 if (*pcGlyphs != prevCount)
855 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
856 i = nextIndex;
858 else
859 i+=write_dir;
862 return *pcGlyphs;
864 return GSUB_E_NOFEATURE;
867 static void GPOS_apply_feature(const ScriptCache *psc, const OUTLINETEXTMETRICW *otm,
868 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance,
869 const LoadedFeature *feature, const WORD *glyphs, int glyph_count, GOFFSET *goffset)
871 int dir = analysis->fLogicalOrder && analysis->fRTL ? -1 : 1;
872 unsigned int start_idx, i, j;
874 TRACE("%i lookups\n", feature->lookup_count);
876 start_idx = dir < 0 ? glyph_count - 1 : 0;
877 for (i = 0; i < feature->lookup_count; i++)
879 for (j = 0; j < glyph_count; )
880 j += OpenType_apply_GPOS_lookup(psc, otm, logfont, analysis, advance,
881 feature->lookups[i], glyphs, start_idx + dir * j, glyph_count, goffset);
885 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
887 OPENTYPE_TAG tag;
888 HRESULT hr;
889 int count = 0;
891 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
893 return(SUCCEEDED(hr));
896 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
898 int i;
899 for (i = *pcGlyphs; i>=index; i--)
900 pwGlyphs[i+1] = pwGlyphs[i];
901 pwGlyphs[index] = glyph;
902 *pcGlyphs = *pcGlyphs+1;
903 if (write_dir < 0)
904 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
905 else
906 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
909 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)
911 CHAR *context_type;
912 int i,g;
913 WCHAR invalid = 0x25cc;
914 WORD invalid_glyph;
916 context_type = heap_alloc(cChars);
918 /* Mark invalid combinations */
919 for (i = 0; i < cChars; i++)
920 context_type[i] = lex(pwcChars[i]);
922 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
923 for (i = 1, g=1; i < cChars - 1; i++, g++)
925 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
927 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
928 g++;
932 heap_free(context_type);
935 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
937 int i;
938 for (i=0; i < cChars; i++)
940 switch (pwcChars[i])
942 case 0x000A:
943 case 0x000D:
944 pwOutGlyphs[i] = psc->sfp.wgBlank;
945 break;
946 default:
947 if (pwcChars[i] < 0x1C)
948 pwOutGlyphs[i] = psc->sfp.wgDefault;
949 else
950 pwOutGlyphs[i] = psc->sfp.wgBlank;
955 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
957 if (i + delta < 0)
958 return 0;
959 if ( i+ delta >= cchLen)
960 return 0;
962 i += delta;
964 return chars[i];
967 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
969 if (i + delta < 0)
971 if (psa->fLinkBefore)
972 return jtR;
973 else
974 return jtU;
976 if ( i+ delta >= cchLen)
978 if (psa->fLinkAfter)
979 return jtL;
980 else
981 return jtU;
984 i += delta;
986 if (context_type[i] == jtT)
987 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
988 else
989 return context_type[i];
992 static inline BOOL right_join_causing(CHAR joining_type)
994 return joining_type == jtL || joining_type == jtD;
997 static inline BOOL left_join_causing(CHAR joining_type)
999 return joining_type == jtR || joining_type == jtD;
1002 static inline BOOL word_break_causing(WCHAR chr)
1004 /* we are working within a string of characters already guaranteed to
1005 be within one script, Syriac, so we do not worry about any character
1006 other than the space character outside of that range */
1007 return (chr == 0 || chr == 0x20 );
1010 static int combining_lexical_Arabic(WCHAR c)
1012 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1014 switch(c)
1016 case 0x064B:
1017 case 0x064C:
1018 case 0x064E:
1019 case 0x064F:
1020 case 0x0652:
1021 case 0x0657:
1022 case 0x0658:
1023 case 0x06E1: return Arab_DIAC1;
1024 case 0x064D:
1025 case 0x0650:
1026 case 0x0656: return Arab_DIAC2;
1027 case 0x0651: return Arab_DIAC3;
1028 case 0x0610:
1029 case 0x0611:
1030 case 0x0612:
1031 case 0x0613:
1032 case 0x0614:
1033 case 0x0659:
1034 case 0x06D6:
1035 case 0x06DC:
1036 case 0x06DF:
1037 case 0x06E0:
1038 case 0x06E2:
1039 case 0x06E4:
1040 case 0x06E7:
1041 case 0x06E8:
1042 case 0x06EB:
1043 case 0x06EC: return Arab_DIAC4;
1044 case 0x06E3:
1045 case 0x06EA:
1046 case 0x06ED: return Arab_DIAC5;
1047 case 0x0670: return Arab_DIAC6;
1048 case 0x0653: return Arab_DIAC7;
1049 case 0x0655:
1050 case 0x0654: return Arab_DIAC8;
1051 default: return Arab_Norm;
1056 * ContextualShape_Arabic
1058 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1060 CHAR *context_type;
1061 INT *context_shape;
1062 INT dirR, dirL;
1063 int i;
1064 int char_index;
1065 int glyph_index;
1067 if (*pcGlyphs != cChars)
1069 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1070 return;
1073 if (psa->fLogicalOrder && psa->fRTL)
1075 dirR = -1;
1076 dirL = 1;
1078 else
1080 dirR = 1;
1081 dirL = -1;
1084 load_ot_tables(hdc, psc);
1086 context_type = heap_alloc(cChars);
1087 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1089 for (i = 0; i < cChars; i++)
1090 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1092 for (i = 0; i < cChars; i++)
1094 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1095 context_shape[i] = Xr;
1096 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1097 context_shape[i] = Xl;
1098 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)))
1099 context_shape[i] = Xm;
1100 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1101 context_shape[i] = Xr;
1102 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1103 context_shape[i] = Xl;
1104 else
1105 context_shape[i] = Xn;
1108 /* Contextual Shaping */
1109 if (dirL > 0)
1110 char_index = glyph_index = 0;
1111 else
1112 char_index = glyph_index = cChars-1;
1114 while(char_index < cChars && char_index >= 0)
1116 BOOL shaped = FALSE;
1118 if (psc->GSUB_Table)
1120 INT nextIndex, offset = 0;
1121 INT prevCount = *pcGlyphs;
1123 /* Apply CCMP first */
1124 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1126 if (prevCount != *pcGlyphs)
1128 offset = *pcGlyphs - prevCount;
1129 if (dirL < 0)
1130 glyph_index -= offset * dirL;
1133 /* Apply the contextual feature */
1134 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1136 if (nextIndex > GSUB_E_NOGLYPH)
1138 UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1139 char_index += dirL;
1140 if (!offset)
1141 glyph_index = nextIndex;
1142 else
1144 offset = *pcGlyphs - prevCount;
1145 glyph_index += dirL * (offset + 1);
1147 shaped = TRUE;
1149 else if (nextIndex == GSUB_E_NOGLYPH)
1151 char_index += dirL;
1152 glyph_index += dirL;
1153 shaped = TRUE;
1157 if (!shaped)
1159 if (context_shape[char_index] == Xn)
1161 WORD newGlyph = pwOutGlyphs[glyph_index];
1162 if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
1164 /* fall back to presentation form B */
1165 WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
1166 if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1167 pwOutGlyphs[glyph_index] = newGlyph;
1170 char_index += dirL;
1171 glyph_index += dirL;
1175 heap_free(context_shape);
1176 heap_free(context_type);
1178 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1181 static int combining_lexical_Hebrew(WCHAR c)
1183 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};
1185 switch(c)
1187 case 0x05B0:
1188 case 0x05B1:
1189 case 0x05B2:
1190 case 0x05B3:
1191 case 0x05B4:
1192 case 0x05B5:
1193 case 0x05B6:
1194 case 0x05BB: return Hebr_DIAC;
1195 case 0x0599:
1196 case 0x05A1:
1197 case 0x05A9:
1198 case 0x05AE: return Hebr_CANT1;
1199 case 0x0597:
1200 case 0x05A8:
1201 case 0x05AC: return Hebr_CANT2;
1202 case 0x0592:
1203 case 0x0593:
1204 case 0x0594:
1205 case 0x0595:
1206 case 0x05A7:
1207 case 0x05AB: return Hebr_CANT3;
1208 case 0x0598:
1209 case 0x059C:
1210 case 0x059E:
1211 case 0x059F: return Hebr_CANT4;
1212 case 0x059D:
1213 case 0x05A0: return Hebr_CANT5;
1214 case 0x059B:
1215 case 0x05A5: return Hebr_CANT6;
1216 case 0x0591:
1217 case 0x05A3:
1218 case 0x05A6: return Hebr_CANT7;
1219 case 0x0596:
1220 case 0x05A4:
1221 case 0x05AA: return Hebr_CANT8;
1222 case 0x059A:
1223 case 0x05AD: return Hebr_CANT9;
1224 case 0x05AF: return Hebr_CANT10;
1225 case 0x05BC: return Hebr_DAGESH;
1226 case 0x05C4: return Hebr_DOTABV;
1227 case 0x05B9: return Hebr_HOLAM;
1228 case 0x05BD: return Hebr_METEG;
1229 case 0x05B7: return Hebr_PATAH;
1230 case 0x05B8: return Hebr_QAMATS;
1231 case 0x05BF: return Hebr_RAFE;
1232 case 0x05C1:
1233 case 0x05C2: return Hebr_SHINSIN;
1234 default: return Hebr_Norm;
1238 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1240 INT dirL;
1242 if (*pcGlyphs != cChars)
1244 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1245 return;
1248 if (!psa->fLogicalOrder && psa->fRTL)
1249 dirL = -1;
1250 else
1251 dirL = 1;
1253 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1257 * ContextualShape_Syriac
1260 static int combining_lexical_Syriac(WCHAR c)
1262 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};
1264 switch(c)
1266 case 0x730:
1267 case 0x733:
1268 case 0x736:
1269 case 0x73A:
1270 case 0x73D: return Syriac_DIAC1;
1271 case 0x731:
1272 case 0x734:
1273 case 0x737:
1274 case 0x73B:
1275 case 0x73E: return Syriac_DIAC2;
1276 case 0x740:
1277 case 0x749:
1278 case 0x74A: return Syriac_DIAC3;
1279 case 0x732:
1280 case 0x735:
1281 case 0x73F: return Syriac_DIAC4;
1282 case 0x738:
1283 case 0x739:
1284 case 0x73C: return Syriac_DIAC5;
1285 case 0x741:
1286 case 0x30A: return Syriac_DIAC6;
1287 case 0x742:
1288 case 0x325: return Syriac_DIAC7;
1289 case 0x747:
1290 case 0x303: return Syriac_DIAC8;
1291 case 0x748:
1292 case 0x32D:
1293 case 0x32E:
1294 case 0x330:
1295 case 0x331: return Syriac_DIAC9;
1296 case 0x308: return Syriac_DIAC10;
1297 case 0x304: return Syriac_DIAC11;
1298 case 0x307: return Syriac_DIAC12;
1299 case 0x323: return Syriac_DIAC13;
1300 case 0x743: return Syriac_DIAC14;
1301 case 0x744: return Syriac_DIAC15;
1302 case 0x745: return Syriac_DIAC16;
1303 case 0x746: return Syriac_DIAC17;
1304 default: return Syriac_Norm;
1308 #define ALAPH 0x710
1309 #define DALATH 0x715
1310 #define RISH 0x72A
1312 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1314 CHAR *context_type;
1315 INT *context_shape;
1316 INT dirR, dirL;
1317 int i;
1318 int char_index;
1319 int glyph_index;
1321 if (*pcGlyphs != cChars)
1323 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1324 return;
1327 if (!psa->fLogicalOrder && psa->fRTL)
1329 dirR = 1;
1330 dirL = -1;
1332 else
1334 dirR = -1;
1335 dirL = 1;
1338 load_ot_tables(hdc, psc);
1340 if (!psc->GSUB_Table)
1341 return;
1343 context_type = heap_alloc(cChars);
1344 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1346 for (i = 0; i < cChars; i++)
1347 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1349 for (i = 0; i < cChars; i++)
1351 if (pwcChars[i] == ALAPH)
1353 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1355 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1356 context_shape[i] = Afj;
1357 else if ( rchar != DALATH && rchar != RISH &&
1358 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1359 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1360 context_shape[i] = Afn;
1361 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1362 context_shape[i] = Afx;
1363 else
1364 context_shape[i] = Xn;
1366 else if (context_type[i] == jtR &&
1367 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1368 context_shape[i] = Xr;
1369 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1370 context_shape[i] = Xl;
1371 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)))
1372 context_shape[i] = Xm;
1373 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1374 context_shape[i] = Xr;
1375 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1376 context_shape[i] = Xl;
1377 else
1378 context_shape[i] = Xn;
1381 /* Contextual Shaping */
1382 if (dirL > 0)
1383 char_index = glyph_index = 0;
1384 else
1385 char_index = glyph_index = cChars-1;
1387 while(char_index < cChars && char_index >= 0)
1389 INT nextIndex, offset = 0;
1390 INT prevCount = *pcGlyphs;
1392 /* Apply CCMP first */
1393 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1395 if (prevCount != *pcGlyphs)
1397 offset = *pcGlyphs - prevCount;
1398 if (dirL < 0)
1399 glyph_index -= offset * dirL;
1402 /* Apply the contextual feature */
1403 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1404 if (nextIndex > GSUB_E_NOGLYPH)
1406 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1407 char_index += dirL;
1408 if (!offset)
1409 glyph_index = nextIndex;
1410 else
1412 offset = *pcGlyphs - prevCount;
1413 glyph_index += dirL * (offset + 1);
1416 else
1418 char_index += dirL;
1419 glyph_index += dirL;
1423 heap_free(context_shape);
1424 heap_free(context_type);
1426 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1429 static int combining_lexical_Thaana(WCHAR c)
1431 enum {Thaana_Norm=0, Thaana_FILI};
1433 switch(c)
1435 case 0x7A6:
1436 case 0x7A7:
1437 case 0x7A8:
1438 case 0x7A9:
1439 case 0x7AA:
1440 case 0x7AB:
1441 case 0x7AC:
1442 case 0x7AD:
1443 case 0x7AE:
1444 case 0x7AF: return Thaana_FILI;
1445 default: return Thaana_Norm;
1449 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1451 INT dirL;
1453 if (*pcGlyphs != cChars)
1455 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1456 return;
1459 if (!psa->fLogicalOrder && psa->fRTL)
1460 dirL = -1;
1461 else
1462 dirL = 1;
1464 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1468 * ContextualShape_Phags_pa
1471 #define phags_pa_CANDRABINDU 0xA873
1472 #define phags_pa_START 0xA840
1473 #define phags_pa_END 0xA87F
1475 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1477 INT *context_shape;
1478 INT dirR, dirL;
1479 int i;
1480 int char_index;
1481 int glyph_index;
1483 if (*pcGlyphs != cChars)
1485 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1486 return;
1489 if (!psa->fLogicalOrder && psa->fRTL)
1491 dirR = 1;
1492 dirL = -1;
1494 else
1496 dirR = -1;
1497 dirL = 1;
1500 load_ot_tables(hdc, psc);
1502 if (!psc->GSUB_Table)
1503 return;
1505 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1507 for (i = 0; i < cChars; i++)
1509 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1511 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1512 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1513 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1514 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1516 if (jrchar && jlchar)
1517 context_shape[i] = Xm;
1518 else if (jrchar)
1519 context_shape[i] = Xr;
1520 else if (jlchar)
1521 context_shape[i] = Xl;
1522 else
1523 context_shape[i] = Xn;
1525 else
1526 context_shape[i] = -1;
1529 /* Contextual Shaping */
1530 if (dirL > 0)
1531 char_index = glyph_index = 0;
1532 else
1533 char_index = glyph_index = cChars-1;
1535 while(char_index < cChars && char_index >= 0)
1537 if (context_shape[char_index] >= 0)
1539 INT nextIndex;
1540 INT prevCount = *pcGlyphs;
1541 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1543 if (nextIndex > GSUB_E_NOGLYPH)
1545 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1546 glyph_index = nextIndex;
1547 char_index += dirL;
1549 else
1551 char_index += dirL;
1552 glyph_index += dirL;
1555 else
1557 char_index += dirL;
1558 glyph_index += dirL;
1562 heap_free(context_shape);
1565 static int combining_lexical_Thai(WCHAR c)
1567 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1569 switch(c)
1571 case 0xE31:
1572 case 0xE34:
1573 case 0xE35:
1574 case 0xE36:
1575 case 0xE37: return Thai_ABOVE1;
1576 case 0xE47:
1577 case 0xE4D: return Thai_ABOVE2;
1578 case 0xE48:
1579 case 0xE49:
1580 case 0xE4A:
1581 case 0xE4B: return Thai_ABOVE3;
1582 case 0xE4C:
1583 case 0xE4E: return Thai_ABOVE4;
1584 case 0xE38:
1585 case 0xE39: return Thai_BELOW1;
1586 case 0xE3A: return Thai_BELOW2;
1587 case 0xE33: return Thai_AM;
1588 default: return Thai_Norm;
1592 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1594 INT dirL;
1596 if (*pcGlyphs != cChars)
1598 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1599 return;
1602 if (!psa->fLogicalOrder && psa->fRTL)
1603 dirL = -1;
1604 else
1605 dirL = 1;
1607 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1610 static int combining_lexical_Lao(WCHAR c)
1612 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1614 switch(c)
1616 case 0xEB1:
1617 case 0xEB4:
1618 case 0xEB5:
1619 case 0xEB6:
1620 case 0xEB7:
1621 case 0xEBB:
1622 case 0xECD: return Lao_ABOVE1;
1623 case 0xEC8:
1624 case 0xEC9:
1625 case 0xECA:
1626 case 0xECB:
1627 case 0xECC: return Lao_ABOVE2;
1628 case 0xEBC: return Lao_BELOW1;
1629 case 0xEB8:
1630 case 0xEB9: return Lao_BELOW2;
1631 case 0xEB3: return Lao_AM;
1632 default: return Lao_Norm;
1636 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1638 INT dirL;
1640 if (*pcGlyphs != cChars)
1642 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1643 return;
1646 if (!psa->fLogicalOrder && psa->fRTL)
1647 dirL = -1;
1648 else
1649 dirL = 1;
1651 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1654 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1656 int i;
1658 /* Replace */
1659 pwOutChars[cWalk] = replacements[0];
1660 cWalk=cWalk+1;
1662 /* Insert */
1663 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1665 int j;
1666 for (j = *pcChars; j > cWalk; j--)
1667 pwOutChars[j] = pwOutChars[j-1];
1668 *pcChars= *pcChars+1;
1669 pwOutChars[cWalk] = replacements[i];
1670 cWalk = cWalk+1;
1674 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1676 int i;
1677 int cWalk;
1679 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1681 for (i = 0; vowels[i].base != 0x0; i++)
1683 if (pwOutChars[cWalk] == vowels[i].base)
1685 int o = 0;
1686 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1687 if (vowels[i].parts[1]) { cWalk++; o++; }
1688 if (vowels[i].parts[2]) { cWalk++; o++; }
1689 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1690 break;
1696 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1698 int i;
1699 int offset = 0;
1700 int cWalk;
1702 for (cWalk = 0; cWalk < *pcChars; cWalk += 2)
1704 for (i = 0; consonants[i].output!= 0x0; i++)
1706 int j;
1707 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1708 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1709 break;
1711 if (consonants[i].parts[j]==0x0) /* matched all */
1713 int k;
1714 j--;
1715 pwOutChars[cWalk] = consonants[i].output;
1716 for(k = cWalk+1; k < *pcChars - j; k++)
1717 pwOutChars[k] = pwOutChars[k+j];
1718 *pcChars = *pcChars - j;
1719 for (k = j ; k > 0; k--)
1720 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1721 offset += j;
1722 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1723 pwLogClust[k]--;
1724 break;
1730 static void Reorder_Ra_follows_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1732 if (s->ralf >= 0)
1734 int j;
1735 WORD Ra = pwChar[s->start];
1736 WORD H = pwChar[s->start+1];
1738 TRACE("Doing reorder of Ra to %i\n",s->base);
1739 for (j = s->start; j < s->base-1; j++)
1740 pwChar[j] = pwChar[j+2];
1741 pwChar[s->base-1] = Ra;
1742 pwChar[s->base] = H;
1744 s->ralf = s->base-1;
1745 s->base -= 2;
1749 static void Reorder_Ra_follows_matra(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1751 if (s->ralf >= 0)
1753 int j,loc;
1754 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1755 WORD Ra = pwChar[s->start];
1756 WORD H = pwChar[s->start+1];
1757 for (loc = s->end; loc > stop; loc--)
1758 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1759 break;
1761 TRACE("Doing reorder of Ra to %i\n",loc);
1762 for (j = s->start; j < loc-1; j++)
1763 pwChar[j] = pwChar[j+2];
1764 pwChar[loc-1] = Ra;
1765 pwChar[loc] = H;
1767 s->ralf = loc-1;
1768 s->base -= 2;
1769 if (s->blwf >= 0) s->blwf -= 2;
1770 if (s->pref >= 0) s->pref -= 2;
1774 static void Reorder_Ra_follows_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1776 if (s->ralf >= 0)
1778 int j;
1779 WORD Ra = pwChar[s->start];
1780 WORD H = pwChar[s->start+1];
1782 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1783 for (j = s->start; j < s->end-1; j++)
1784 pwChar[j] = pwChar[j+2];
1785 pwChar[s->end-1] = Ra;
1786 pwChar[s->end] = H;
1788 s->ralf = s->end-1;
1789 s->base -= 2;
1790 if (s->blwf >= 0) s->blwf -= 2;
1791 if (s->pref >= 0) s->pref -= 2;
1795 static void Reorder_Matra_precede_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1797 int i;
1799 /* reorder Matras */
1800 if (s->end > s->base)
1802 for (i = 1; i <= s->end-s->base; i++)
1804 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1806 int j;
1807 WCHAR c = pwChar[s->base+i];
1808 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1809 for (j = s->base+i; j > s->base; j--)
1810 pwChar[j] = pwChar[j-1];
1811 pwChar[s->base] = c;
1813 if (s->ralf >= s->base) s->ralf++;
1814 if (s->blwf >= s->base) s->blwf++;
1815 if (s->pref >= s->base) s->pref++;
1816 s->base ++;
1822 static void Reorder_Matra_precede_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1824 int i;
1826 /* reorder Matras */
1827 if (s->end > s->base)
1829 for (i = 1; i <= s->end-s->base; i++)
1831 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1833 int j;
1834 WCHAR c = pwChar[s->base+i];
1835 TRACE("Doing reorder of %x to %i\n",c,s->start);
1836 for (j = s->base+i; j > s->start; j--)
1837 pwChar[j] = pwChar[j-1];
1838 pwChar[s->start] = c;
1840 if (s->ralf >= 0) s->ralf++;
1841 if (s->blwf >= 0) s->blwf++;
1842 if (s->pref >= 0) s->pref++;
1843 s->base ++;
1849 static void SecondReorder_Blwf_follows_matra(const WCHAR *chars, const IndicSyllable *s,
1850 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1852 if (s->blwf >= 0 && g->blwf > g->base)
1854 int j,loc;
1855 int g_offset;
1856 for (loc = s->end; loc > s->blwf; loc--)
1857 if (lexical(chars[loc]) == lex_Matra_below || lexical(chars[loc]) == lex_Matra_above
1858 || lexical(chars[loc]) == lex_Matra_post)
1859 break;
1861 g_offset = (loc - s->blwf) - 1;
1863 if (loc != s->blwf)
1865 WORD blwf = glyphs[g->blwf];
1866 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1867 /* do not care about the pwChar array anymore, just the glyphs */
1868 for (j = 0; j < g_offset; j++)
1869 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1870 glyphs[g->blwf + g_offset] = blwf;
1875 static void SecondReorder_Matra_precede_base(const WCHAR *chars, const IndicSyllable *s,
1876 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1878 int i;
1880 /* reorder previously moved Matras to correct position*/
1881 for (i = s->start; i < s->base; i++)
1883 if (lexical(chars[i]) == lex_Matra_pre)
1885 int j;
1886 int g_start = g->start + i - s->start;
1887 if (g_start < g->base -1 )
1889 WCHAR og = glyphs[g_start];
1890 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1891 for (j = g_start; j < g->base-1; j++)
1892 glyphs[j] = glyphs[j+1];
1893 glyphs[g->base-1] = og;
1899 static void SecondReorder_Pref_precede_base(const IndicSyllable *s,
1900 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1902 if (s->pref >= 0 && g->pref > g->base)
1904 int j;
1905 WCHAR og = glyphs[g->pref];
1906 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1907 for (j = g->pref; j > g->base; j--)
1908 glyphs[j] = glyphs[j-1];
1909 glyphs[g->base] = og;
1913 static void Reorder_Like_Sinhala(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1915 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1916 if (s->start == s->base && s->base == s->end) return;
1917 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1919 Reorder_Ra_follows_base(pwChar, s, lexical);
1920 Reorder_Matra_precede_base(pwChar, s, lexical);
1923 static void Reorder_Like_Devanagari(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1925 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1926 if (s->start == s->base && s->base == s->end) return;
1927 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1929 Reorder_Ra_follows_matra(pwChar, s, lexical);
1930 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1933 static void Reorder_Like_Bengali(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1935 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1936 if (s->start == s->base && s->base == s->end) return;
1937 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1939 Reorder_Ra_follows_base(pwChar, s, lexical);
1940 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1943 static void Reorder_Like_Kannada(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1945 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1946 if (s->start == s->base && s->base == s->end) return;
1947 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1949 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1950 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1953 static void SecondReorder_Like_Telugu(const WCHAR *chars, const IndicSyllable *s,
1954 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1956 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1957 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1958 if (s->start == s->base && s->base == s->end) return;
1959 if (lexical(chars[s->base]) == lex_Vowel) return;
1961 SecondReorder_Blwf_follows_matra(chars, s, glyphs, g, lexical);
1964 static void SecondReorder_Like_Tamil(const WCHAR *chars, const IndicSyllable *s,
1965 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1967 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1968 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1969 if (s->start == s->base && s->base == s->end) return;
1970 if (lexical(chars[s->base]) == lex_Vowel) return;
1972 SecondReorder_Matra_precede_base(chars, s, glyphs, g, lexical);
1973 SecondReorder_Pref_precede_base(s, glyphs, g, lexical);
1977 static inline void shift_syllable_glyph_indices(IndicSyllable *glyph_index, INT index, INT shift)
1979 if (shift == 0)
1980 return;
1982 if (glyph_index->start > index)
1983 glyph_index->start += shift;
1984 if (glyph_index->base > index)
1985 glyph_index->base+= shift;
1986 if (glyph_index->end > index)
1987 glyph_index->end+= shift;
1988 if (glyph_index->ralf > index)
1989 glyph_index->ralf+= shift;
1990 if (glyph_index->blwf > index)
1991 glyph_index->blwf+= shift;
1992 if (glyph_index->pref > index)
1993 glyph_index->pref+= shift;
1996 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 )
1998 int index = glyph_index->start;
2000 if (!feature)
2001 return;
2003 while(index <= glyph_index->end)
2005 INT nextIndex;
2006 INT prevCount = *pcGlyphs;
2007 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2008 if (nextIndex > GSUB_E_NOGLYPH)
2010 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2011 shift_syllable_glyph_indices(glyph_index,index,*pcGlyphs - prevCount);
2012 index = nextIndex;
2014 else
2015 index++;
2019 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2021 int i = 0;
2022 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)))))
2023 i++;
2024 if (index + i <= end-1)
2025 return index + i;
2026 else
2027 return -1;
2030 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)
2032 INT index, nextIndex;
2033 INT count,g_offset;
2035 count = syllable->base - syllable->start;
2037 g_offset = 0;
2038 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2039 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2041 INT prevCount = *pcGlyphs;
2042 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2043 if (nextIndex > GSUB_E_NOGLYPH)
2045 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2046 shift_syllable_glyph_indices(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2047 g_offset += (*pcGlyphs - prevCount);
2050 index+=2;
2051 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2055 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)
2057 INT nextIndex;
2058 INT prevCount = *pcGlyphs;
2060 if (syllable->ralf >= 0)
2062 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2063 if (nextIndex > GSUB_E_NOGLYPH)
2065 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2066 shift_syllable_glyph_indices(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2071 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2073 int i = 0;
2074 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2075 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2076 is_consonant(lexical(pwChars[index+i+1])))))
2077 i++;
2078 if (index + i <= end-1)
2079 return index+i;
2080 else
2081 return -1;
2084 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)
2086 INT index, nextIndex;
2087 INT count, g_offset=0;
2088 INT ralf = syllable->ralf;
2090 count = syllable->end - syllable->base;
2092 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2094 while (index >= 0)
2096 INT prevCount = *pcGlyphs;
2097 if (ralf >=0 && ralf < index)
2099 g_offset--;
2100 ralf = -1;
2103 if (!modern)
2105 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2106 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2107 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2110 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2111 if (nextIndex > GSUB_E_NOGLYPH)
2113 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2114 shift_syllable_glyph_indices(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2115 g_offset += (*pcGlyphs - prevCount);
2117 else if (!modern)
2119 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2120 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2121 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2124 index+=2;
2125 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2129 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)
2131 int c;
2132 int overall_shift = 0;
2133 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2134 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2135 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2136 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2137 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2138 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2139 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2140 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2141 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2142 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2143 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2144 IndicSyllable glyph_indices;
2146 for (c = 0; c < syllable_count; c++)
2148 int old_end;
2149 memcpy(&glyph_indices, &syllables[c], sizeof(IndicSyllable));
2150 shift_syllable_glyph_indices(&glyph_indices, -1, overall_shift);
2151 old_end = glyph_indices.end;
2153 if (locl)
2155 TRACE("applying feature locl\n");
2156 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, locl);
2158 if (nukt)
2160 TRACE("applying feature nukt\n");
2161 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, nukt);
2163 if (akhn)
2165 TRACE("applying feature akhn\n");
2166 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, akhn);
2169 if (rphf)
2170 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices);
2171 if (rkrf)
2173 TRACE("applying feature rkrf\n");
2174 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, rkrf);
2176 if (pref)
2177 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, modern, "pref");
2178 if (blwf)
2180 if (!modern)
2181 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, "blwf");
2183 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, modern, "blwf");
2186 if (half)
2187 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, "half");
2188 if (pstf)
2190 TRACE("applying feature pstf\n");
2191 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, pstf);
2193 if (vatu)
2195 TRACE("applying feature vatu\n");
2196 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, vatu);
2198 if (cjct)
2200 TRACE("applying feature cjct\n");
2201 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, cjct);
2204 if (second_reorder)
2205 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indices, lexical);
2207 overall_shift += glyph_indices.end - old_end;
2211 static inline int unicode_lex(WCHAR c)
2213 int type;
2215 if (!c) return lex_Generic;
2216 if (c == 0x200D) return lex_ZWJ;
2217 if (c == 0x200C) return lex_ZWNJ;
2218 if (c == 0x00A0) return lex_NBSP;
2220 type = get_table_entry( indic_syllabic_table, c );
2222 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2224 switch( type )
2226 case 0x0d07: /* Unknown */
2227 case 0x0e07: /* Unknown */
2228 default: return lex_Generic;
2229 case 0x0001:
2230 case 0x0002:
2231 case 0x0011:
2232 case 0x0012:
2233 case 0x0013:
2234 case 0x0014: return lex_Modifier;
2235 case 0x0003:
2236 case 0x0009:
2237 case 0x000a:
2238 case 0x000b:
2239 case 0x000d:
2240 case 0x000e:
2241 case 0x000f:
2242 case 0x0010: return lex_Consonant;
2243 case 0x0004: return lex_Nukta;
2244 case 0x0005: return lex_Halant;
2245 case 0x0006:
2246 case 0x0008: return lex_Vowel;
2247 case 0x0007:
2248 case 0x0107: return lex_Matra_post;
2249 case 0x0207:
2250 case 0x0307: return lex_Matra_pre;
2251 case 0x0807:
2252 case 0x0907:
2253 case 0x0a07:
2254 case 0x0b07:
2255 case 0x0c07:
2256 case 0x0f07:
2257 case 0x1007:
2258 case 0x0407: return lex_Composed_Vowel;
2259 case 0x0507: return lex_Matra_above;
2260 case 0x0607: return lex_Matra_below;
2261 case 0x000c:
2262 case 0x0015: return lex_Ra;
2266 static int sinhala_lex(WCHAR c)
2268 switch (c)
2270 case 0x0DDA:
2271 case 0x0DDD:
2272 case 0x0DDC:
2273 case 0x0DDE: return lex_Matra_post;
2274 default:
2275 return unicode_lex(c);
2279 static const VowelComponents Sinhala_vowels[] = {
2280 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2281 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2282 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2283 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2284 {0x0000, {0x0000,0x0000,0x0}}};
2286 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2288 int cCount = cChars;
2289 int i;
2290 WCHAR *input;
2291 IndicSyllable *syllables = NULL;
2292 int syllable_count = 0;
2294 if (*pcGlyphs != cChars)
2296 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2297 return;
2300 input = heap_alloc(3 * cChars * sizeof(*input));
2302 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2304 /* Step 1: Decompose multi part vowels */
2305 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2307 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2309 /* Step 2: Reorder within Syllables */
2310 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2311 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2313 /* Step 3: Strip dangling joiners */
2314 for (i = 0; i < cCount; i++)
2316 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2317 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2318 input[i] = 0x0020;
2321 /* Step 4: Base Form application to syllables */
2322 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2323 *pcGlyphs = cCount;
2324 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2326 heap_free(input);
2327 heap_free(syllables);
2330 static int devanagari_lex(WCHAR c)
2332 switch (c)
2334 case 0x0930: return lex_Ra;
2335 default:
2336 return unicode_lex(c);
2340 static const ConsonantComponents Devanagari_consonants[] ={
2341 {{0x0928, 0x093C, 0x00000}, 0x0929},
2342 {{0x0930, 0x093C, 0x00000}, 0x0931},
2343 {{0x0933, 0x093C, 0x00000}, 0x0934},
2344 {{0x0915, 0x093C, 0x00000}, 0x0958},
2345 {{0x0916, 0x093C, 0x00000}, 0x0959},
2346 {{0x0917, 0x093C, 0x00000}, 0x095A},
2347 {{0x091C, 0x093C, 0x00000}, 0x095B},
2348 {{0x0921, 0x093C, 0x00000}, 0x095C},
2349 {{0x0922, 0x093C, 0x00000}, 0x095D},
2350 {{0x092B, 0x093C, 0x00000}, 0x095E},
2351 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2353 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2355 int cCount = cChars;
2356 WCHAR *input;
2357 IndicSyllable *syllables = NULL;
2358 int syllable_count = 0;
2359 BOOL modern = get_GSUB_Indic2(psa, psc);
2361 if (*pcGlyphs != cChars)
2363 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2364 return;
2367 input = heap_alloc(cChars * sizeof(*input));
2368 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2370 /* Step 1: Compose Consonant and Nukta */
2371 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2372 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2374 /* Step 2: Reorder within Syllables */
2375 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2376 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2377 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2378 *pcGlyphs = cCount;
2380 /* Step 3: Base Form application to syllables */
2381 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2383 heap_free(input);
2384 heap_free(syllables);
2387 static int bengali_lex(WCHAR c)
2389 switch (c)
2391 case 0x09B0: return lex_Ra;
2392 default:
2393 return unicode_lex(c);
2397 static const VowelComponents Bengali_vowels[] = {
2398 {0x09CB, {0x09C7,0x09BE,0x0000}},
2399 {0x09CC, {0x09C7,0x09D7,0x0000}},
2400 {0x0000, {0x0000,0x0000,0x0000}}};
2402 static const ConsonantComponents Bengali_consonants[] = {
2403 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2404 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2405 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2406 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2407 {{0x0000,0x0000,0x0000}, 0x0000}};
2409 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2411 int cCount = cChars;
2412 WCHAR *input;
2413 IndicSyllable *syllables = NULL;
2414 int syllable_count = 0;
2415 BOOL modern = get_GSUB_Indic2(psa, psc);
2417 if (*pcGlyphs != cChars)
2419 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2420 return;
2423 input = heap_alloc(2 * cChars * sizeof(*input));
2424 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2426 /* Step 1: Decompose Vowels and Compose Consonants */
2427 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2428 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2429 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2431 /* Step 2: Reorder within Syllables */
2432 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2433 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2434 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2435 *pcGlyphs = cCount;
2437 /* Step 3: Initial form is only applied to the beginning of words */
2438 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2440 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2442 int index = cCount;
2443 int gCount = 1;
2444 if (index > 0) index++;
2446 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2450 /* Step 4: Base Form application to syllables */
2451 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2453 heap_free(input);
2454 heap_free(syllables);
2457 static int gurmukhi_lex(WCHAR c)
2459 if (c == 0x0A71)
2460 return lex_Modifier;
2461 else
2462 return unicode_lex(c);
2465 static const ConsonantComponents Gurmukhi_consonants[] = {
2466 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2467 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2468 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2469 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2470 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2471 {{0x0000,0x0000,0x0000}, 0x0000}};
2473 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2475 int cCount = cChars;
2476 WCHAR *input;
2477 IndicSyllable *syllables = NULL;
2478 int syllable_count = 0;
2479 BOOL modern = get_GSUB_Indic2(psa, psc);
2481 if (*pcGlyphs != cChars)
2483 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2484 return;
2487 input = heap_alloc(cChars * sizeof(*input));
2488 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2490 /* Step 1: Compose Consonants */
2491 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2492 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2494 /* Step 2: Reorder within Syllables */
2495 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2496 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2497 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2498 *pcGlyphs = cCount;
2500 /* Step 3: Base Form application to syllables */
2501 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2503 heap_free(input);
2504 heap_free(syllables);
2507 static int gujarati_lex(WCHAR c)
2509 switch (c)
2511 case 0x0AB0: return lex_Ra;
2512 default:
2513 return unicode_lex(c);
2517 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2519 int cCount = cChars;
2520 WCHAR *input;
2521 IndicSyllable *syllables = NULL;
2522 int syllable_count = 0;
2523 BOOL modern = get_GSUB_Indic2(psa, psc);
2525 if (*pcGlyphs != cChars)
2527 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2528 return;
2531 input = heap_alloc(cChars * sizeof(*input));
2532 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2534 /* Step 1: Reorder within Syllables */
2535 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2536 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2537 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2538 *pcGlyphs = cCount;
2540 /* Step 2: Base Form application to syllables */
2541 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2543 heap_free(input);
2544 heap_free(syllables);
2547 static int oriya_lex(WCHAR c)
2549 switch (c)
2551 case 0x0B30: return lex_Ra;
2552 default:
2553 return unicode_lex(c);
2557 static const VowelComponents Oriya_vowels[] = {
2558 {0x0B48, {0x0B47,0x0B56,0x0000}},
2559 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2560 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2561 {0x0000, {0x0000,0x0000,0x0000}}};
2563 static const ConsonantComponents Oriya_consonants[] = {
2564 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2565 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2566 {{0x0000,0x0000,0x0000}, 0x0000}};
2568 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2570 int cCount = cChars;
2571 WCHAR *input;
2572 IndicSyllable *syllables = NULL;
2573 int syllable_count = 0;
2574 BOOL modern = get_GSUB_Indic2(psa, psc);
2576 if (*pcGlyphs != cChars)
2578 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2579 return;
2582 input = heap_alloc(2 * cChars * sizeof(*input));
2583 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2585 /* Step 1: Decompose Vowels and Compose Consonants */
2586 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2587 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2588 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2590 /* Step 2: Reorder within Syllables */
2591 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2592 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2593 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2594 *pcGlyphs = cCount;
2596 /* Step 3: Base Form application to syllables */
2597 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2599 heap_free(input);
2600 heap_free(syllables);
2603 static int tamil_lex(WCHAR c)
2605 return unicode_lex(c);
2608 static const VowelComponents Tamil_vowels[] = {
2609 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2610 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2611 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2612 {0x0000, {0x0000,0x0000,0x0000}}};
2614 static const ConsonantComponents Tamil_consonants[] = {
2615 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2616 {{0x0000,0x0000,0x0000}, 0x0000}};
2618 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2620 int cCount = cChars;
2621 WCHAR *input;
2622 IndicSyllable *syllables = NULL;
2623 int syllable_count = 0;
2624 BOOL modern = get_GSUB_Indic2(psa, psc);
2626 if (*pcGlyphs != cChars)
2628 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2629 return;
2632 input = heap_alloc(2 * cChars * sizeof(*input));
2633 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2635 /* Step 1: Decompose Vowels and Compose Consonants */
2636 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2637 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2638 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2640 /* Step 2: Reorder within Syllables */
2641 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2642 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2643 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2644 *pcGlyphs = cCount;
2646 /* Step 3: Base Form application to syllables */
2647 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2649 heap_free(input);
2650 heap_free(syllables);
2653 static int telugu_lex(WCHAR c)
2655 switch (c)
2657 case 0x0C43:
2658 case 0x0C44: return lex_Modifier;
2659 default:
2660 return unicode_lex(c);
2664 static const VowelComponents Telugu_vowels[] = {
2665 {0x0C48, {0x0C46,0x0C56,0x0000}},
2666 {0x0000, {0x0000,0x0000,0x0000}}};
2668 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2670 int cCount = cChars;
2671 WCHAR *input;
2672 IndicSyllable *syllables = NULL;
2673 int syllable_count = 0;
2674 BOOL modern = get_GSUB_Indic2(psa, psc);
2676 if (*pcGlyphs != cChars)
2678 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2679 return;
2682 input = heap_alloc(2 * cChars * sizeof(*input));
2683 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2685 /* Step 1: Decompose Vowels */
2686 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2687 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2689 /* Step 2: Reorder within Syllables */
2690 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2691 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2692 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2693 *pcGlyphs = cCount;
2695 /* Step 3: Base Form application to syllables */
2696 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2698 heap_free(input);
2699 heap_free(syllables);
2702 static int kannada_lex(WCHAR c)
2704 switch (c)
2706 case 0x0CB0: return lex_Ra;
2707 default:
2708 return unicode_lex(c);
2712 static const VowelComponents Kannada_vowels[] = {
2713 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2714 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2715 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2716 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2717 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2718 {0x0000, {0x0000,0x0000,0x0000}}};
2720 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2722 int cCount = cChars;
2723 WCHAR *input;
2724 IndicSyllable *syllables = NULL;
2725 int syllable_count = 0;
2726 BOOL modern = get_GSUB_Indic2(psa, psc);
2728 if (*pcGlyphs != cChars)
2730 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2731 return;
2734 input = heap_alloc(3 * cChars * sizeof(*input));
2735 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2737 /* Step 1: Decompose Vowels */
2738 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2739 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2741 /* Step 2: Reorder within Syllables */
2742 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2743 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2744 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2745 *pcGlyphs = cCount;
2747 /* Step 3: Base Form application to syllables */
2748 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2750 heap_free(input);
2751 heap_free(syllables);
2754 static int malayalam_lex(WCHAR c)
2756 return unicode_lex(c);
2759 static const VowelComponents Malayalam_vowels[] = {
2760 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2761 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2762 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2763 {0x0000, {0x0000,0x0000,0x0000}}};
2765 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2767 int cCount = cChars;
2768 WCHAR *input;
2769 IndicSyllable *syllables = NULL;
2770 int syllable_count = 0;
2771 BOOL modern = get_GSUB_Indic2(psa, psc);
2773 if (*pcGlyphs != cChars)
2775 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2776 return;
2779 input = heap_alloc(2 * cChars * sizeof(*input));
2780 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2782 /* Step 1: Decompose Vowels */
2783 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2784 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2786 /* Step 2: Reorder within Syllables */
2787 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2788 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2789 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2790 *pcGlyphs = cCount;
2792 /* Step 3: Base Form application to syllables */
2793 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2795 heap_free(input);
2796 heap_free(syllables);
2799 static int khmer_lex(WCHAR c)
2801 return unicode_lex(c);
2804 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2806 int cCount = cChars;
2807 WCHAR *input;
2808 IndicSyllable *syllables = NULL;
2809 int syllable_count = 0;
2811 if (*pcGlyphs != cChars)
2813 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2814 return;
2817 input = heap_alloc(cChars * sizeof(*input));
2818 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2820 /* Step 1: Reorder within Syllables */
2821 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2822 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2823 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2824 *pcGlyphs = cCount;
2826 /* Step 2: Base Form application to syllables */
2827 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2829 heap_free(input);
2830 heap_free(syllables);
2833 static inline BOOL mongolian_wordbreak(WCHAR chr)
2835 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2838 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2840 INT *context_shape;
2841 INT dirL;
2842 int i;
2843 int char_index;
2844 int glyph_index;
2846 if (*pcGlyphs != cChars)
2848 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2849 return;
2852 if (!psa->fLogicalOrder && psa->fRTL)
2853 dirL = -1;
2854 else
2855 dirL = 1;
2857 if (!psc->GSUB_Table)
2858 return;
2860 context_shape = heap_alloc(cChars * sizeof(*context_shape));
2862 for (i = 0; i < cChars; i++)
2864 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2866 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2867 context_shape[i] = Xn;
2868 else
2869 context_shape[i] = Xl;
2871 else
2873 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2874 context_shape[i] = Xr;
2875 else
2876 context_shape[i] = Xm;
2880 /* Contextual Shaping */
2881 if (dirL > 0)
2882 char_index = glyph_index = 0;
2883 else
2884 char_index = glyph_index = cChars-1;
2886 while(char_index < cChars && char_index >= 0)
2888 INT nextIndex;
2889 INT prevCount = *pcGlyphs;
2890 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2892 if (nextIndex > GSUB_E_NOGLYPH)
2894 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2895 glyph_index = nextIndex;
2896 char_index += dirL;
2898 else
2900 char_index += dirL;
2901 glyph_index += dirL;
2905 heap_free(context_shape);
2908 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)
2910 int i,k;
2912 for (i = 0; i < cGlyphs; i++)
2914 int char_index[20];
2915 int char_count = 0;
2917 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2918 if (k>=0)
2920 for (; k < cChars && pwLogClust[k] == i; k++)
2921 char_index[char_count++] = k;
2924 if (char_count == 0)
2925 continue;
2927 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2929 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2930 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2932 else
2933 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2936 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2937 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2940 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 )
2942 int i;
2944 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2946 for (i = 0; i < cGlyphs; i++)
2947 if (pGlyphProp[i].sva.fZeroWidth)
2948 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2951 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 )
2953 int i;
2954 for (i = 0; i < cGlyphs; i++)
2956 pGlyphProp[i].sva.fClusterStart = 1;
2957 pGlyphProp[i].sva.fDiacritic = 0;
2958 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2960 if (pwGlyphs[i] == psc->sfp.wgDefault)
2961 pGlyphProp[i].sva.fZeroWidth = 0;
2962 else
2963 pGlyphProp[i].sva.fZeroWidth = 1;
2967 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 )
2969 int i,k;
2970 int initGlyph, finaGlyph;
2971 INT dirR, dirL;
2972 BYTE *spaces;
2974 spaces = heap_alloc(cGlyphs);
2975 memset(spaces,0,cGlyphs);
2977 if (psa->fLogicalOrder && psa->fRTL)
2979 initGlyph = 0;
2980 finaGlyph = cGlyphs-1;
2981 dirR = -1;
2982 dirL = 1;
2984 else
2986 initGlyph = cGlyphs-1;
2987 finaGlyph = 0;
2988 dirR = 1;
2989 dirL = -1;
2992 for (i = 0; i < cGlyphs; i++)
2994 for (k = 0; k < cChars; k++)
2995 if (pwLogClust[k] == i)
2997 if (pwcChars[k] == 0x0020)
2998 spaces[i] = 1;
3002 for (i = 0; i < cGlyphs; i++)
3004 int char_index[20];
3005 int char_count = 0;
3006 BOOL isInit, isFinal;
3008 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3009 if (k>=0)
3011 for (; k < cChars && pwLogClust[k] == i; k++)
3012 char_index[char_count++] = k;
3015 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3016 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3018 if (char_count == 0)
3019 continue;
3021 if (char_count == 1)
3023 if (pwcChars[char_index[0]] == 0x0020) /* space */
3025 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3026 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3028 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3029 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3030 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3032 if (!isInit && !isFinal)
3033 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3034 else if (isInit)
3035 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3036 else
3037 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3039 else if (!isInit)
3041 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3042 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3043 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3044 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3045 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3046 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3047 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3048 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3049 else
3050 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3052 else if (!isInit && !isFinal)
3053 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3054 else
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3057 else if (char_count == 2)
3059 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3060 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3061 else if (!isInit)
3062 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3063 else
3064 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3066 else if (!isInit && !isFinal)
3067 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3068 else
3069 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3072 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3073 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3074 heap_free(spaces);
3077 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 )
3079 int i,k;
3081 for (i = 0; i < cGlyphs; i++)
3083 int char_index[20];
3084 int char_count = 0;
3086 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3087 if (k>=0)
3089 for (; k < cChars && pwLogClust[k] == i; k++)
3090 char_index[char_count++] = k;
3093 if (char_count == 0)
3094 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3095 else
3097 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3098 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3099 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3103 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3104 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3107 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 )
3109 int i;
3110 int finaGlyph;
3111 INT dirL;
3113 if (!psa->fLogicalOrder && psa->fRTL)
3115 finaGlyph = 0;
3116 dirL = -1;
3118 else
3120 finaGlyph = cGlyphs-1;
3121 dirL = 1;
3124 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3126 for (i = 0; i < cGlyphs; i++)
3128 int k;
3129 int char_index[20];
3130 int char_count = 0;
3132 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3133 if (k>=0)
3135 for (; k < cChars && pwLogClust[k] == i; k++)
3136 char_index[char_count++] = k;
3139 if (i == finaGlyph)
3140 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3141 else
3142 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3144 if (char_count == 0)
3145 continue;
3147 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3148 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3150 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3151 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3152 pGlyphProp[i].sva.fClusterStart = 0;
3155 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3157 /* Do not allow justification between marks and their base */
3158 for (i = 0; i < cGlyphs; i++)
3160 if (!pGlyphProp[i].sva.fClusterStart)
3161 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3165 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)
3167 int i,k;
3169 for (i = 0; i < cGlyphs; i++)
3171 int char_index[20];
3172 int char_count = 0;
3174 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3175 if (k>=0)
3177 for (; k < cChars && pwLogClust[k] == i; k++)
3178 char_index[char_count++] = k;
3181 if (char_count == 0)
3182 continue;
3184 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3186 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3187 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3189 else
3190 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3192 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3193 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3196 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)
3198 int i,k;
3200 for (i = 0; i < cGlyphs; i++)
3202 int char_index[20];
3203 int char_count = 0;
3205 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3206 if (k>=0)
3208 for (; k < cChars && pwLogClust[k] == i; k++)
3209 char_index[char_count++] = k;
3212 if (char_count == 0)
3213 continue;
3215 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3217 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3218 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3220 else
3221 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3223 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3224 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3226 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3227 for (i = 0; i < cGlyphs; i++)
3229 if (!pGlyphProp[i].sva.fClusterStart)
3231 pGlyphProp[i].sva.fDiacritic = 0;
3232 pGlyphProp[i].sva.fZeroWidth = 0;
3237 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)
3239 int i,k;
3241 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3242 for (i = 0; i < cGlyphs; i++)
3244 int char_index[20];
3245 int char_count = 0;
3247 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3248 if (k>=0)
3250 for (; k < cChars && pwLogClust[k] == i; k++)
3251 char_index[char_count++] = k;
3254 if (override_gsub)
3256 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3257 pGlyphProp[i].sva.fDiacritic = FALSE;
3258 pGlyphProp[i].sva.fZeroWidth = FALSE;
3261 if (char_count == 0)
3263 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3264 continue;
3267 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3269 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3270 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3272 else
3273 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3275 pGlyphProp[i].sva.fClusterStart = 0;
3276 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3277 switch (lexical(pwcChars[char_index[k]]))
3279 case lex_Matra_pre:
3280 case lex_Matra_post:
3281 case lex_Matra_above:
3282 case lex_Matra_below:
3283 case lex_Modifier:
3284 case lex_Halant:
3285 break;
3286 case lex_ZWJ:
3287 case lex_ZWNJ:
3288 /* check for dangling joiners */
3289 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3290 pGlyphProp[i].sva.fClusterStart = 1;
3291 else
3292 k = char_count;
3293 break;
3294 default:
3295 pGlyphProp[i].sva.fClusterStart = 1;
3296 break;
3300 if (use_syllables)
3302 IndicSyllable *syllables = NULL;
3303 int syllable_count = 0;
3304 BOOL modern = get_GSUB_Indic2(psa, psc);
3306 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3308 for (i = 0; i < syllable_count; i++)
3310 int j;
3311 WORD g = pwLogClust[syllables[i].start];
3312 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3314 if (pwLogClust[j] != g)
3316 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3317 pwLogClust[j] = g;
3322 heap_free(syllables);
3325 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3328 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 )
3330 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3333 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 )
3335 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3338 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 )
3340 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3343 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 )
3345 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3348 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 )
3350 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3353 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 )
3355 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3358 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 )
3360 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3363 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 )
3365 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3368 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 )
3370 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3373 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 )
3375 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3378 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 )
3380 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3383 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)
3385 load_ot_tables(hdc, psc);
3387 if (ShapingData[psa->eScript].charGlyphPropProc)
3388 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3389 else
3390 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3393 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3395 load_ot_tables(hdc, psc);
3397 if (ShapingData[psa->eScript].contextProc)
3398 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3401 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)
3403 int i;
3404 INT dirL;
3406 if (!rpRangeProperties)
3407 return;
3409 load_ot_tables(hdc, psc);
3411 if (!psc->GSUB_Table)
3412 return;
3414 if (scriptInformation[psa->eScript].a.fRTL && (!psa->fLogicalOrder || !psa->fRTL))
3415 dirL = -1;
3416 else
3417 dirL = 1;
3419 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3421 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3422 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3426 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3428 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3429 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3431 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3434 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3436 const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3437 int i;
3439 load_ot_tables(hdc, psc);
3441 if (!psc->GPOS_Table || !psc->otm)
3442 return;
3444 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3446 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3448 LoadedFeature *feature;
3450 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3451 if (!feature)
3452 continue;
3454 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3459 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3461 LoadedFeature *feature;
3462 int i;
3464 if (!ShapingData[psa->eScript].requiredFeatures)
3465 return S_OK;
3467 load_ot_tables(hdc, psc);
3469 /* we need to have at least one of the required features */
3470 i = 0;
3471 while (ShapingData[psa->eScript].requiredFeatures[i])
3473 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3474 if (feature)
3475 return S_OK;
3476 i++;
3479 return USP_E_SCRIPT_NOT_IN_FONT;
3482 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3483 SCRIPT_ANALYSIS *psa, int cMaxTags,
3484 OPENTYPE_TAG *pScriptTags, int *pcTags)
3486 HRESULT hr;
3487 OPENTYPE_TAG searching = 0x00000000;
3489 load_ot_tables(hdc, psc);
3491 if (psa && scriptInformation[psa->eScript].scriptTag)
3492 searching = scriptInformation[psa->eScript].scriptTag;
3494 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3495 if (FAILED(hr))
3496 *pcTags = 0;
3497 return hr;
3500 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3501 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3502 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3503 int *pcTags)
3505 HRESULT hr;
3506 OPENTYPE_TAG searching = 0x00000000;
3507 BOOL fellback = FALSE;
3509 load_ot_tables(hdc, psc);
3511 if (psa && psc->userLang != 0)
3512 searching = psc->userLang;
3514 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3515 if (FAILED(hr))
3517 fellback = TRUE;
3518 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3521 if (FAILED(hr) || fellback)
3522 *pcTags = 0;
3523 if (SUCCEEDED(hr) && fellback && psa)
3524 hr = E_INVALIDARG;
3525 return hr;
3528 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3529 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3530 OPENTYPE_TAG tagLangSys, int cMaxTags,
3531 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3533 HRESULT hr;
3534 BOOL filter = FALSE;
3536 load_ot_tables(hdc, psc);
3538 if (psa && scriptInformation[psa->eScript].scriptTag)
3540 FIXME("Filtering not implemented\n");
3541 filter = TRUE;
3544 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3546 if (FAILED(hr))
3547 *pcTags = 0;
3548 return hr;