kernelbase: Let GetModuleBaseName succeed on 64bit modules in wow64.
[wine.git] / dlls / gdi32 / uniscribe / shape.c
blob912d3e6965b6c7a716fe249c5b75fbc6cfd1c0fb
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 "ntgdi.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 = NtGdiGetTextCharsetInfo(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 = NtGdiGetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
673 if (length != GDI_ERROR)
675 GSUB_Table = heap_alloc(length);
676 NtGdiGetFontData(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 = NtGdiGetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
686 if (length != GDI_ERROR)
688 GPOS_Table = heap_alloc(length);
689 NtGdiGetFontData(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 = NtGdiGetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
699 if (length != GDI_ERROR)
701 GDEF_Table = heap_alloc(length);
702 NtGdiGetFontData(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 NtGdiGetGlyphIndicesW(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 NtGdiGetGlyphIndicesW(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_16( 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] &&
1167 NtGdiGetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR &&
1168 newGlyph != 0x0000)
1169 pwOutGlyphs[glyph_index] = newGlyph;
1172 char_index += dirL;
1173 glyph_index += dirL;
1177 heap_free(context_shape);
1178 heap_free(context_type);
1180 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1183 static int combining_lexical_Hebrew(WCHAR c)
1185 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};
1187 switch(c)
1189 case 0x05B0:
1190 case 0x05B1:
1191 case 0x05B2:
1192 case 0x05B3:
1193 case 0x05B4:
1194 case 0x05B5:
1195 case 0x05B6:
1196 case 0x05BB: return Hebr_DIAC;
1197 case 0x0599:
1198 case 0x05A1:
1199 case 0x05A9:
1200 case 0x05AE: return Hebr_CANT1;
1201 case 0x0597:
1202 case 0x05A8:
1203 case 0x05AC: return Hebr_CANT2;
1204 case 0x0592:
1205 case 0x0593:
1206 case 0x0594:
1207 case 0x0595:
1208 case 0x05A7:
1209 case 0x05AB: return Hebr_CANT3;
1210 case 0x0598:
1211 case 0x059C:
1212 case 0x059E:
1213 case 0x059F: return Hebr_CANT4;
1214 case 0x059D:
1215 case 0x05A0: return Hebr_CANT5;
1216 case 0x059B:
1217 case 0x05A5: return Hebr_CANT6;
1218 case 0x0591:
1219 case 0x05A3:
1220 case 0x05A6: return Hebr_CANT7;
1221 case 0x0596:
1222 case 0x05A4:
1223 case 0x05AA: return Hebr_CANT8;
1224 case 0x059A:
1225 case 0x05AD: return Hebr_CANT9;
1226 case 0x05AF: return Hebr_CANT10;
1227 case 0x05BC: return Hebr_DAGESH;
1228 case 0x05C4: return Hebr_DOTABV;
1229 case 0x05B9: return Hebr_HOLAM;
1230 case 0x05BD: return Hebr_METEG;
1231 case 0x05B7: return Hebr_PATAH;
1232 case 0x05B8: return Hebr_QAMATS;
1233 case 0x05BF: return Hebr_RAFE;
1234 case 0x05C1:
1235 case 0x05C2: return Hebr_SHINSIN;
1236 default: return Hebr_Norm;
1240 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1242 INT dirL;
1244 if (*pcGlyphs != cChars)
1246 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1247 return;
1250 if (!psa->fLogicalOrder && psa->fRTL)
1251 dirL = -1;
1252 else
1253 dirL = 1;
1255 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1259 * ContextualShape_Syriac
1262 static int combining_lexical_Syriac(WCHAR c)
1264 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};
1266 switch(c)
1268 case 0x730:
1269 case 0x733:
1270 case 0x736:
1271 case 0x73A:
1272 case 0x73D: return Syriac_DIAC1;
1273 case 0x731:
1274 case 0x734:
1275 case 0x737:
1276 case 0x73B:
1277 case 0x73E: return Syriac_DIAC2;
1278 case 0x740:
1279 case 0x749:
1280 case 0x74A: return Syriac_DIAC3;
1281 case 0x732:
1282 case 0x735:
1283 case 0x73F: return Syriac_DIAC4;
1284 case 0x738:
1285 case 0x739:
1286 case 0x73C: return Syriac_DIAC5;
1287 case 0x741:
1288 case 0x30A: return Syriac_DIAC6;
1289 case 0x742:
1290 case 0x325: return Syriac_DIAC7;
1291 case 0x747:
1292 case 0x303: return Syriac_DIAC8;
1293 case 0x748:
1294 case 0x32D:
1295 case 0x32E:
1296 case 0x330:
1297 case 0x331: return Syriac_DIAC9;
1298 case 0x308: return Syriac_DIAC10;
1299 case 0x304: return Syriac_DIAC11;
1300 case 0x307: return Syriac_DIAC12;
1301 case 0x323: return Syriac_DIAC13;
1302 case 0x743: return Syriac_DIAC14;
1303 case 0x744: return Syriac_DIAC15;
1304 case 0x745: return Syriac_DIAC16;
1305 case 0x746: return Syriac_DIAC17;
1306 default: return Syriac_Norm;
1310 #define ALAPH 0x710
1311 #define DALATH 0x715
1312 #define RISH 0x72A
1314 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1316 CHAR *context_type;
1317 INT *context_shape;
1318 INT dirR, dirL;
1319 int i;
1320 int char_index;
1321 int glyph_index;
1323 if (*pcGlyphs != cChars)
1325 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1326 return;
1329 if (!psa->fLogicalOrder && psa->fRTL)
1331 dirR = 1;
1332 dirL = -1;
1334 else
1336 dirR = -1;
1337 dirL = 1;
1340 load_ot_tables(hdc, psc);
1342 if (!psc->GSUB_Table)
1343 return;
1345 context_type = heap_alloc(cChars);
1346 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1348 for (i = 0; i < cChars; i++)
1349 context_type[i] = get_table_entry_16( wine_shaping_table, pwcChars[i] );
1351 for (i = 0; i < cChars; i++)
1353 if (pwcChars[i] == ALAPH)
1355 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1357 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1358 context_shape[i] = Afj;
1359 else if ( rchar != DALATH && rchar != RISH &&
1360 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1361 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1362 context_shape[i] = Afn;
1363 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1364 context_shape[i] = Afx;
1365 else
1366 context_shape[i] = Xn;
1368 else if (context_type[i] == jtR &&
1369 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1370 context_shape[i] = Xr;
1371 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1372 context_shape[i] = Xl;
1373 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)))
1374 context_shape[i] = Xm;
1375 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1376 context_shape[i] = Xr;
1377 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1378 context_shape[i] = Xl;
1379 else
1380 context_shape[i] = Xn;
1383 /* Contextual Shaping */
1384 if (dirL > 0)
1385 char_index = glyph_index = 0;
1386 else
1387 char_index = glyph_index = cChars-1;
1389 while(char_index < cChars && char_index >= 0)
1391 INT nextIndex, offset = 0;
1392 INT prevCount = *pcGlyphs;
1394 /* Apply CCMP first */
1395 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1397 if (prevCount != *pcGlyphs)
1399 offset = *pcGlyphs - prevCount;
1400 if (dirL < 0)
1401 glyph_index -= offset * dirL;
1404 /* Apply the contextual feature */
1405 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1406 if (nextIndex > GSUB_E_NOGLYPH)
1408 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1409 char_index += dirL;
1410 if (!offset)
1411 glyph_index = nextIndex;
1412 else
1414 offset = *pcGlyphs - prevCount;
1415 glyph_index += dirL * (offset + 1);
1418 else
1420 char_index += dirL;
1421 glyph_index += dirL;
1425 heap_free(context_shape);
1426 heap_free(context_type);
1428 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1431 static int combining_lexical_Thaana(WCHAR c)
1433 enum {Thaana_Norm=0, Thaana_FILI};
1435 switch(c)
1437 case 0x7A6:
1438 case 0x7A7:
1439 case 0x7A8:
1440 case 0x7A9:
1441 case 0x7AA:
1442 case 0x7AB:
1443 case 0x7AC:
1444 case 0x7AD:
1445 case 0x7AE:
1446 case 0x7AF: return Thaana_FILI;
1447 default: return Thaana_Norm;
1451 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1453 INT dirL;
1455 if (*pcGlyphs != cChars)
1457 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1458 return;
1461 if (!psa->fLogicalOrder && psa->fRTL)
1462 dirL = -1;
1463 else
1464 dirL = 1;
1466 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1470 * ContextualShape_Phags_pa
1473 #define phags_pa_CANDRABINDU 0xA873
1474 #define phags_pa_START 0xA840
1475 #define phags_pa_END 0xA87F
1477 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1479 INT *context_shape;
1480 INT dirR, dirL;
1481 int i;
1482 int char_index;
1483 int glyph_index;
1485 if (*pcGlyphs != cChars)
1487 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1488 return;
1491 if (!psa->fLogicalOrder && psa->fRTL)
1493 dirR = 1;
1494 dirL = -1;
1496 else
1498 dirR = -1;
1499 dirL = 1;
1502 load_ot_tables(hdc, psc);
1504 if (!psc->GSUB_Table)
1505 return;
1507 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1509 for (i = 0; i < cChars; i++)
1511 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1513 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1514 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1515 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1516 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1518 if (jrchar && jlchar)
1519 context_shape[i] = Xm;
1520 else if (jrchar)
1521 context_shape[i] = Xr;
1522 else if (jlchar)
1523 context_shape[i] = Xl;
1524 else
1525 context_shape[i] = Xn;
1527 else
1528 context_shape[i] = -1;
1531 /* Contextual Shaping */
1532 if (dirL > 0)
1533 char_index = glyph_index = 0;
1534 else
1535 char_index = glyph_index = cChars-1;
1537 while(char_index < cChars && char_index >= 0)
1539 if (context_shape[char_index] >= 0)
1541 INT nextIndex;
1542 INT prevCount = *pcGlyphs;
1543 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1545 if (nextIndex > GSUB_E_NOGLYPH)
1547 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1548 glyph_index = nextIndex;
1549 char_index += dirL;
1551 else
1553 char_index += dirL;
1554 glyph_index += dirL;
1557 else
1559 char_index += dirL;
1560 glyph_index += dirL;
1564 heap_free(context_shape);
1567 static int combining_lexical_Thai(WCHAR c)
1569 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1571 switch(c)
1573 case 0xE31:
1574 case 0xE34:
1575 case 0xE35:
1576 case 0xE36:
1577 case 0xE37: return Thai_ABOVE1;
1578 case 0xE47:
1579 case 0xE4D: return Thai_ABOVE2;
1580 case 0xE48:
1581 case 0xE49:
1582 case 0xE4A:
1583 case 0xE4B: return Thai_ABOVE3;
1584 case 0xE4C:
1585 case 0xE4E: return Thai_ABOVE4;
1586 case 0xE38:
1587 case 0xE39: return Thai_BELOW1;
1588 case 0xE3A: return Thai_BELOW2;
1589 case 0xE33: return Thai_AM;
1590 default: return Thai_Norm;
1594 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1596 INT dirL;
1598 if (*pcGlyphs != cChars)
1600 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1601 return;
1604 if (!psa->fLogicalOrder && psa->fRTL)
1605 dirL = -1;
1606 else
1607 dirL = 1;
1609 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1612 static int combining_lexical_Lao(WCHAR c)
1614 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1616 switch(c)
1618 case 0xEB1:
1619 case 0xEB4:
1620 case 0xEB5:
1621 case 0xEB6:
1622 case 0xEB7:
1623 case 0xEBB:
1624 case 0xECD: return Lao_ABOVE1;
1625 case 0xEC8:
1626 case 0xEC9:
1627 case 0xECA:
1628 case 0xECB:
1629 case 0xECC: return Lao_ABOVE2;
1630 case 0xEBC: return Lao_BELOW1;
1631 case 0xEB8:
1632 case 0xEB9: return Lao_BELOW2;
1633 case 0xEB3: return Lao_AM;
1634 default: return Lao_Norm;
1638 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1640 INT dirL;
1642 if (*pcGlyphs != cChars)
1644 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1645 return;
1648 if (!psa->fLogicalOrder && psa->fRTL)
1649 dirL = -1;
1650 else
1651 dirL = 1;
1653 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1656 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1658 int i;
1660 /* Replace */
1661 pwOutChars[cWalk] = replacements[0];
1662 cWalk=cWalk+1;
1664 /* Insert */
1665 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1667 int j;
1668 for (j = *pcChars; j > cWalk; j--)
1669 pwOutChars[j] = pwOutChars[j-1];
1670 *pcChars= *pcChars+1;
1671 pwOutChars[cWalk] = replacements[i];
1672 cWalk = cWalk+1;
1676 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1678 int i;
1679 int cWalk;
1681 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1683 for (i = 0; vowels[i].base != 0x0; i++)
1685 if (pwOutChars[cWalk] == vowels[i].base)
1687 int o = 0;
1688 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1689 if (vowels[i].parts[1]) { cWalk++; o++; }
1690 if (vowels[i].parts[2]) { cWalk++; o++; }
1691 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1692 break;
1698 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1700 int i;
1701 int offset = 0;
1702 int cWalk;
1704 for (cWalk = 0; cWalk < *pcChars; cWalk += 2)
1706 for (i = 0; consonants[i].output!= 0x0; i++)
1708 int j;
1709 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1710 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1711 break;
1713 if (consonants[i].parts[j]==0x0) /* matched all */
1715 int k;
1716 j--;
1717 pwOutChars[cWalk] = consonants[i].output;
1718 for(k = cWalk+1; k < *pcChars - j; k++)
1719 pwOutChars[k] = pwOutChars[k+j];
1720 *pcChars = *pcChars - j;
1721 for (k = j ; k > 0; k--)
1722 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1723 offset += j;
1724 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1725 pwLogClust[k]--;
1726 break;
1732 static void Reorder_Ra_follows_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1734 if (s->ralf >= 0)
1736 int j;
1737 WORD Ra = pwChar[s->start];
1738 WORD H = pwChar[s->start+1];
1740 TRACE("Doing reorder of Ra to %i\n",s->base);
1741 for (j = s->start; j < s->base-1; j++)
1742 pwChar[j] = pwChar[j+2];
1743 pwChar[s->base-1] = Ra;
1744 pwChar[s->base] = H;
1746 s->ralf = s->base-1;
1747 s->base -= 2;
1751 static void Reorder_Ra_follows_matra(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1753 if (s->ralf >= 0)
1755 int j,loc;
1756 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1757 WORD Ra = pwChar[s->start];
1758 WORD H = pwChar[s->start+1];
1759 for (loc = s->end; loc > stop; loc--)
1760 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1761 break;
1763 TRACE("Doing reorder of Ra to %i\n",loc);
1764 for (j = s->start; j < loc-1; j++)
1765 pwChar[j] = pwChar[j+2];
1766 pwChar[loc-1] = Ra;
1767 pwChar[loc] = H;
1769 s->ralf = loc-1;
1770 s->base -= 2;
1771 if (s->blwf >= 0) s->blwf -= 2;
1772 if (s->pref >= 0) s->pref -= 2;
1776 static void Reorder_Ra_follows_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1778 if (s->ralf >= 0)
1780 int j;
1781 WORD Ra = pwChar[s->start];
1782 WORD H = pwChar[s->start+1];
1784 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1785 for (j = s->start; j < s->end-1; j++)
1786 pwChar[j] = pwChar[j+2];
1787 pwChar[s->end-1] = Ra;
1788 pwChar[s->end] = H;
1790 s->ralf = s->end-1;
1791 s->base -= 2;
1792 if (s->blwf >= 0) s->blwf -= 2;
1793 if (s->pref >= 0) s->pref -= 2;
1797 static void Reorder_Matra_precede_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1799 int i;
1801 /* reorder Matras */
1802 if (s->end > s->base)
1804 for (i = 1; i <= s->end-s->base; i++)
1806 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1808 int j;
1809 WCHAR c = pwChar[s->base+i];
1810 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1811 for (j = s->base+i; j > s->base; j--)
1812 pwChar[j] = pwChar[j-1];
1813 pwChar[s->base] = c;
1815 if (s->ralf >= s->base) s->ralf++;
1816 if (s->blwf >= s->base) s->blwf++;
1817 if (s->pref >= s->base) s->pref++;
1818 s->base ++;
1824 static void Reorder_Matra_precede_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1826 int i;
1828 /* reorder Matras */
1829 if (s->end > s->base)
1831 for (i = 1; i <= s->end-s->base; i++)
1833 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1835 int j;
1836 WCHAR c = pwChar[s->base+i];
1837 TRACE("Doing reorder of %x to %i\n",c,s->start);
1838 for (j = s->base+i; j > s->start; j--)
1839 pwChar[j] = pwChar[j-1];
1840 pwChar[s->start] = c;
1842 if (s->ralf >= 0) s->ralf++;
1843 if (s->blwf >= 0) s->blwf++;
1844 if (s->pref >= 0) s->pref++;
1845 s->base ++;
1851 static void SecondReorder_Blwf_follows_matra(const WCHAR *chars, const IndicSyllable *s,
1852 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1854 if (s->blwf >= 0 && g->blwf > g->base)
1856 int j,loc;
1857 int g_offset;
1858 for (loc = s->end; loc > s->blwf; loc--)
1859 if (lexical(chars[loc]) == lex_Matra_below || lexical(chars[loc]) == lex_Matra_above
1860 || lexical(chars[loc]) == lex_Matra_post)
1861 break;
1863 g_offset = (loc - s->blwf) - 1;
1865 if (loc != s->blwf)
1867 WORD blwf = glyphs[g->blwf];
1868 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1869 /* do not care about the pwChar array anymore, just the glyphs */
1870 for (j = 0; j < g_offset; j++)
1871 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1872 glyphs[g->blwf + g_offset] = blwf;
1877 static void SecondReorder_Matra_precede_base(const WCHAR *chars, const IndicSyllable *s,
1878 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1880 int i;
1882 /* reorder previously moved Matras to correct position*/
1883 for (i = s->start; i < s->base; i++)
1885 if (lexical(chars[i]) == lex_Matra_pre)
1887 int j;
1888 int g_start = g->start + i - s->start;
1889 if (g_start < g->base -1 )
1891 WCHAR og = glyphs[g_start];
1892 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1893 for (j = g_start; j < g->base-1; j++)
1894 glyphs[j] = glyphs[j+1];
1895 glyphs[g->base-1] = og;
1901 static void SecondReorder_Pref_precede_base(const IndicSyllable *s,
1902 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1904 if (s->pref >= 0 && g->pref > g->base)
1906 int j;
1907 WCHAR og = glyphs[g->pref];
1908 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1909 for (j = g->pref; j > g->base; j--)
1910 glyphs[j] = glyphs[j-1];
1911 glyphs[g->base] = og;
1915 static void Reorder_Like_Sinhala(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1917 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1918 if (s->start == s->base && s->base == s->end) return;
1919 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1921 Reorder_Ra_follows_base(pwChar, s, lexical);
1922 Reorder_Matra_precede_base(pwChar, s, lexical);
1925 static void Reorder_Like_Devanagari(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1927 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1928 if (s->start == s->base && s->base == s->end) return;
1929 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1931 Reorder_Ra_follows_matra(pwChar, s, lexical);
1932 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1935 static void Reorder_Like_Bengali(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1937 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1938 if (s->start == s->base && s->base == s->end) return;
1939 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1941 Reorder_Ra_follows_base(pwChar, s, lexical);
1942 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1945 static void Reorder_Like_Kannada(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1947 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1948 if (s->start == s->base && s->base == s->end) return;
1949 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1951 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1952 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1955 static void SecondReorder_Like_Telugu(const WCHAR *chars, const IndicSyllable *s,
1956 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1958 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1959 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1960 if (s->start == s->base && s->base == s->end) return;
1961 if (lexical(chars[s->base]) == lex_Vowel) return;
1963 SecondReorder_Blwf_follows_matra(chars, s, glyphs, g, lexical);
1966 static void SecondReorder_Like_Tamil(const WCHAR *chars, const IndicSyllable *s,
1967 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1969 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1970 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1971 if (s->start == s->base && s->base == s->end) return;
1972 if (lexical(chars[s->base]) == lex_Vowel) return;
1974 SecondReorder_Matra_precede_base(chars, s, glyphs, g, lexical);
1975 SecondReorder_Pref_precede_base(s, glyphs, g, lexical);
1979 static inline void shift_syllable_glyph_indices(IndicSyllable *glyph_index, INT index, INT shift)
1981 if (shift == 0)
1982 return;
1984 if (glyph_index->start > index)
1985 glyph_index->start += shift;
1986 if (glyph_index->base > index)
1987 glyph_index->base+= shift;
1988 if (glyph_index->end > index)
1989 glyph_index->end+= shift;
1990 if (glyph_index->ralf > index)
1991 glyph_index->ralf+= shift;
1992 if (glyph_index->blwf > index)
1993 glyph_index->blwf+= shift;
1994 if (glyph_index->pref > index)
1995 glyph_index->pref+= shift;
1998 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 )
2000 int index = glyph_index->start;
2002 if (!feature)
2003 return;
2005 while(index <= glyph_index->end)
2007 INT nextIndex;
2008 INT prevCount = *pcGlyphs;
2009 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2010 if (nextIndex > GSUB_E_NOGLYPH)
2012 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2013 shift_syllable_glyph_indices(glyph_index,index,*pcGlyphs - prevCount);
2014 index = nextIndex;
2016 else
2017 index++;
2021 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2023 int i = 0;
2024 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)))))
2025 i++;
2026 if (index + i <= end-1)
2027 return index + i;
2028 else
2029 return -1;
2032 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)
2034 INT index, nextIndex;
2035 INT count,g_offset;
2037 count = syllable->base - syllable->start;
2039 g_offset = 0;
2040 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2041 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2043 INT prevCount = *pcGlyphs;
2044 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2045 if (nextIndex > GSUB_E_NOGLYPH)
2047 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2048 shift_syllable_glyph_indices(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2049 g_offset += (*pcGlyphs - prevCount);
2052 index+=2;
2053 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2057 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)
2059 INT nextIndex;
2060 INT prevCount = *pcGlyphs;
2062 if (syllable->ralf >= 0)
2064 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2065 if (nextIndex > GSUB_E_NOGLYPH)
2067 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2068 shift_syllable_glyph_indices(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2073 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2075 int i = 0;
2076 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2077 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2078 is_consonant(lexical(pwChars[index+i+1])))))
2079 i++;
2080 if (index + i <= end-1)
2081 return index+i;
2082 else
2083 return -1;
2086 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)
2088 INT index, nextIndex;
2089 INT count, g_offset=0;
2090 INT ralf = syllable->ralf;
2092 count = syllable->end - syllable->base;
2094 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2096 while (index >= 0)
2098 INT prevCount = *pcGlyphs;
2099 if (ralf >=0 && ralf < index)
2101 g_offset--;
2102 ralf = -1;
2105 if (!modern)
2107 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2108 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2109 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2112 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2113 if (nextIndex > GSUB_E_NOGLYPH)
2115 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2116 shift_syllable_glyph_indices(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2117 g_offset += (*pcGlyphs - prevCount);
2119 else if (!modern)
2121 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2122 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2123 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2126 index+=2;
2127 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2131 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)
2133 int c;
2134 int overall_shift = 0;
2135 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2136 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2137 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2138 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2139 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2140 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2141 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2142 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2143 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2144 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2145 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2146 IndicSyllable glyph_indices;
2148 for (c = 0; c < syllable_count; c++)
2150 int old_end;
2151 memcpy(&glyph_indices, &syllables[c], sizeof(IndicSyllable));
2152 shift_syllable_glyph_indices(&glyph_indices, -1, overall_shift);
2153 old_end = glyph_indices.end;
2155 if (locl)
2157 TRACE("applying feature locl\n");
2158 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, locl);
2160 if (nukt)
2162 TRACE("applying feature nukt\n");
2163 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, nukt);
2165 if (akhn)
2167 TRACE("applying feature akhn\n");
2168 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, akhn);
2171 if (rphf)
2172 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices);
2173 if (rkrf)
2175 TRACE("applying feature rkrf\n");
2176 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, rkrf);
2178 if (pref)
2179 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, modern, "pref");
2180 if (blwf)
2182 if (!modern)
2183 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, "blwf");
2185 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, modern, "blwf");
2188 if (half)
2189 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, "half");
2190 if (pstf)
2192 TRACE("applying feature pstf\n");
2193 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, pstf);
2195 if (vatu)
2197 TRACE("applying feature vatu\n");
2198 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, vatu);
2200 if (cjct)
2202 TRACE("applying feature cjct\n");
2203 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, cjct);
2206 if (second_reorder)
2207 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indices, lexical);
2209 overall_shift += glyph_indices.end - old_end;
2213 static inline int unicode_lex(WCHAR c)
2215 int type;
2217 if (!c) return lex_Generic;
2218 if (c == 0x200D) return lex_ZWJ;
2219 if (c == 0x200C) return lex_ZWNJ;
2220 if (c == 0x00A0) return lex_NBSP;
2222 type = get_table_entry_16( indic_syllabic_table, c );
2224 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2226 switch( type )
2228 case 0x0d07: /* Unknown */
2229 case 0x0e07: /* Unknown */
2230 default: return lex_Generic;
2231 case 0x0001:
2232 case 0x0002:
2233 case 0x0011:
2234 case 0x0012:
2235 case 0x0013:
2236 case 0x0014: return lex_Modifier;
2237 case 0x0003:
2238 case 0x0009:
2239 case 0x000a:
2240 case 0x000b:
2241 case 0x000d:
2242 case 0x000e:
2243 case 0x000f:
2244 case 0x0010: return lex_Consonant;
2245 case 0x0004: return lex_Nukta;
2246 case 0x0005: return lex_Halant;
2247 case 0x0006:
2248 case 0x0008: return lex_Vowel;
2249 case 0x0007:
2250 case 0x0107: return lex_Matra_post;
2251 case 0x0207:
2252 case 0x0307: return lex_Matra_pre;
2253 case 0x0807:
2254 case 0x0907:
2255 case 0x0a07:
2256 case 0x0b07:
2257 case 0x0c07:
2258 case 0x0f07:
2259 case 0x1007:
2260 case 0x0407: return lex_Composed_Vowel;
2261 case 0x0507: return lex_Matra_above;
2262 case 0x0607: return lex_Matra_below;
2263 case 0x000c:
2264 case 0x0015: return lex_Ra;
2268 static int sinhala_lex(WCHAR c)
2270 switch (c)
2272 case 0x0DDA:
2273 case 0x0DDD:
2274 case 0x0DDC:
2275 case 0x0DDE: return lex_Matra_post;
2276 default:
2277 return unicode_lex(c);
2281 static const VowelComponents Sinhala_vowels[] = {
2282 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2283 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2284 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2285 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2286 {0x0000, {0x0000,0x0000,0x0}}};
2288 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2290 int cCount = cChars;
2291 int i;
2292 WCHAR *input;
2293 IndicSyllable *syllables = NULL;
2294 int syllable_count = 0;
2296 if (*pcGlyphs != cChars)
2298 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2299 return;
2302 input = heap_alloc(3 * cChars * sizeof(*input));
2304 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2306 /* Step 1: Decompose multi part vowels */
2307 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2309 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2311 /* Step 2: Reorder within Syllables */
2312 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2313 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2315 /* Step 3: Strip dangling joiners */
2316 for (i = 0; i < cCount; i++)
2318 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2319 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2320 input[i] = 0x0020;
2323 /* Step 4: Base Form application to syllables */
2324 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2325 *pcGlyphs = cCount;
2326 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2328 heap_free(input);
2329 heap_free(syllables);
2332 static int devanagari_lex(WCHAR c)
2334 switch (c)
2336 case 0x0930: return lex_Ra;
2337 default:
2338 return unicode_lex(c);
2342 static const ConsonantComponents Devanagari_consonants[] ={
2343 {{0x0928, 0x093C, 0x00000}, 0x0929},
2344 {{0x0930, 0x093C, 0x00000}, 0x0931},
2345 {{0x0933, 0x093C, 0x00000}, 0x0934},
2346 {{0x0915, 0x093C, 0x00000}, 0x0958},
2347 {{0x0916, 0x093C, 0x00000}, 0x0959},
2348 {{0x0917, 0x093C, 0x00000}, 0x095A},
2349 {{0x091C, 0x093C, 0x00000}, 0x095B},
2350 {{0x0921, 0x093C, 0x00000}, 0x095C},
2351 {{0x0922, 0x093C, 0x00000}, 0x095D},
2352 {{0x092B, 0x093C, 0x00000}, 0x095E},
2353 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2355 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2357 int cCount = cChars;
2358 WCHAR *input;
2359 IndicSyllable *syllables = NULL;
2360 int syllable_count = 0;
2361 BOOL modern = get_GSUB_Indic2(psa, psc);
2363 if (*pcGlyphs != cChars)
2365 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2366 return;
2369 input = heap_alloc(cChars * sizeof(*input));
2370 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2372 /* Step 1: Compose Consonant and Nukta */
2373 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2374 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2376 /* Step 2: Reorder within Syllables */
2377 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2378 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2379 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2380 *pcGlyphs = cCount;
2382 /* Step 3: Base Form application to syllables */
2383 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2385 heap_free(input);
2386 heap_free(syllables);
2389 static int bengali_lex(WCHAR c)
2391 switch (c)
2393 case 0x09B0: return lex_Ra;
2394 default:
2395 return unicode_lex(c);
2399 static const VowelComponents Bengali_vowels[] = {
2400 {0x09CB, {0x09C7,0x09BE,0x0000}},
2401 {0x09CC, {0x09C7,0x09D7,0x0000}},
2402 {0x0000, {0x0000,0x0000,0x0000}}};
2404 static const ConsonantComponents Bengali_consonants[] = {
2405 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2406 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2407 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2408 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2409 {{0x0000,0x0000,0x0000}, 0x0000}};
2411 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2413 int cCount = cChars;
2414 WCHAR *input;
2415 IndicSyllable *syllables = NULL;
2416 int syllable_count = 0;
2417 BOOL modern = get_GSUB_Indic2(psa, psc);
2419 if (*pcGlyphs != cChars)
2421 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2422 return;
2425 input = heap_alloc(2 * cChars * sizeof(*input));
2426 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2428 /* Step 1: Decompose Vowels and Compose Consonants */
2429 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2430 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2431 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2433 /* Step 2: Reorder within Syllables */
2434 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2435 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2436 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2437 *pcGlyphs = cCount;
2439 /* Step 3: Initial form is only applied to the beginning of words */
2440 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2442 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2444 int index = cCount;
2445 int gCount = 1;
2446 if (index > 0) index++;
2448 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2452 /* Step 4: Base Form application to syllables */
2453 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2455 heap_free(input);
2456 heap_free(syllables);
2459 static int gurmukhi_lex(WCHAR c)
2461 if (c == 0x0A71)
2462 return lex_Modifier;
2463 else
2464 return unicode_lex(c);
2467 static const ConsonantComponents Gurmukhi_consonants[] = {
2468 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2469 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2470 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2471 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2472 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2473 {{0x0000,0x0000,0x0000}, 0x0000}};
2475 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2477 int cCount = cChars;
2478 WCHAR *input;
2479 IndicSyllable *syllables = NULL;
2480 int syllable_count = 0;
2481 BOOL modern = get_GSUB_Indic2(psa, psc);
2483 if (*pcGlyphs != cChars)
2485 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2486 return;
2489 input = heap_alloc(cChars * sizeof(*input));
2490 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2492 /* Step 1: Compose Consonants */
2493 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2494 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2496 /* Step 2: Reorder within Syllables */
2497 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2498 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2499 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2500 *pcGlyphs = cCount;
2502 /* Step 3: Base Form application to syllables */
2503 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2505 heap_free(input);
2506 heap_free(syllables);
2509 static int gujarati_lex(WCHAR c)
2511 switch (c)
2513 case 0x0AB0: return lex_Ra;
2514 default:
2515 return unicode_lex(c);
2519 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2521 int cCount = cChars;
2522 WCHAR *input;
2523 IndicSyllable *syllables = NULL;
2524 int syllable_count = 0;
2525 BOOL modern = get_GSUB_Indic2(psa, psc);
2527 if (*pcGlyphs != cChars)
2529 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2530 return;
2533 input = heap_alloc(cChars * sizeof(*input));
2534 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2536 /* Step 1: Reorder within Syllables */
2537 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2538 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2539 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2540 *pcGlyphs = cCount;
2542 /* Step 2: Base Form application to syllables */
2543 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2545 heap_free(input);
2546 heap_free(syllables);
2549 static int oriya_lex(WCHAR c)
2551 switch (c)
2553 case 0x0B30: return lex_Ra;
2554 default:
2555 return unicode_lex(c);
2559 static const VowelComponents Oriya_vowels[] = {
2560 {0x0B48, {0x0B47,0x0B56,0x0000}},
2561 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2562 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2563 {0x0000, {0x0000,0x0000,0x0000}}};
2565 static const ConsonantComponents Oriya_consonants[] = {
2566 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2567 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2568 {{0x0000,0x0000,0x0000}, 0x0000}};
2570 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2572 int cCount = cChars;
2573 WCHAR *input;
2574 IndicSyllable *syllables = NULL;
2575 int syllable_count = 0;
2576 BOOL modern = get_GSUB_Indic2(psa, psc);
2578 if (*pcGlyphs != cChars)
2580 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2581 return;
2584 input = heap_alloc(2 * cChars * sizeof(*input));
2585 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2587 /* Step 1: Decompose Vowels and Compose Consonants */
2588 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2589 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2590 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2592 /* Step 2: Reorder within Syllables */
2593 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2594 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2595 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2596 *pcGlyphs = cCount;
2598 /* Step 3: Base Form application to syllables */
2599 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2601 heap_free(input);
2602 heap_free(syllables);
2605 static int tamil_lex(WCHAR c)
2607 return unicode_lex(c);
2610 static const VowelComponents Tamil_vowels[] = {
2611 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2612 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2613 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2614 {0x0000, {0x0000,0x0000,0x0000}}};
2616 static const ConsonantComponents Tamil_consonants[] = {
2617 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2618 {{0x0000,0x0000,0x0000}, 0x0000}};
2620 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2622 int cCount = cChars;
2623 WCHAR *input;
2624 IndicSyllable *syllables = NULL;
2625 int syllable_count = 0;
2626 BOOL modern = get_GSUB_Indic2(psa, psc);
2628 if (*pcGlyphs != cChars)
2630 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2631 return;
2634 input = heap_alloc(2 * cChars * sizeof(*input));
2635 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2637 /* Step 1: Decompose Vowels and Compose Consonants */
2638 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2639 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2640 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2642 /* Step 2: Reorder within Syllables */
2643 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2644 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2645 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2646 *pcGlyphs = cCount;
2648 /* Step 3: Base Form application to syllables */
2649 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2651 heap_free(input);
2652 heap_free(syllables);
2655 static int telugu_lex(WCHAR c)
2657 switch (c)
2659 case 0x0C43:
2660 case 0x0C44: return lex_Modifier;
2661 default:
2662 return unicode_lex(c);
2666 static const VowelComponents Telugu_vowels[] = {
2667 {0x0C48, {0x0C46,0x0C56,0x0000}},
2668 {0x0000, {0x0000,0x0000,0x0000}}};
2670 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2672 int cCount = cChars;
2673 WCHAR *input;
2674 IndicSyllable *syllables = NULL;
2675 int syllable_count = 0;
2676 BOOL modern = get_GSUB_Indic2(psa, psc);
2678 if (*pcGlyphs != cChars)
2680 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2681 return;
2684 input = heap_alloc(2 * cChars * sizeof(*input));
2685 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2687 /* Step 1: Decompose Vowels */
2688 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2689 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2691 /* Step 2: Reorder within Syllables */
2692 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2693 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2694 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2695 *pcGlyphs = cCount;
2697 /* Step 3: Base Form application to syllables */
2698 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2700 heap_free(input);
2701 heap_free(syllables);
2704 static int kannada_lex(WCHAR c)
2706 switch (c)
2708 case 0x0CB0: return lex_Ra;
2709 default:
2710 return unicode_lex(c);
2714 static const VowelComponents Kannada_vowels[] = {
2715 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2716 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2717 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2718 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2719 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2720 {0x0000, {0x0000,0x0000,0x0000}}};
2722 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2724 int cCount = cChars;
2725 WCHAR *input;
2726 IndicSyllable *syllables = NULL;
2727 int syllable_count = 0;
2728 BOOL modern = get_GSUB_Indic2(psa, psc);
2730 if (*pcGlyphs != cChars)
2732 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2733 return;
2736 input = heap_alloc(3 * cChars * sizeof(*input));
2737 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2739 /* Step 1: Decompose Vowels */
2740 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2741 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2743 /* Step 2: Reorder within Syllables */
2744 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2745 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2746 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2747 *pcGlyphs = cCount;
2749 /* Step 3: Base Form application to syllables */
2750 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2752 heap_free(input);
2753 heap_free(syllables);
2756 static int malayalam_lex(WCHAR c)
2758 return unicode_lex(c);
2761 static const VowelComponents Malayalam_vowels[] = {
2762 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2763 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2764 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2765 {0x0000, {0x0000,0x0000,0x0000}}};
2767 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2769 int cCount = cChars;
2770 WCHAR *input;
2771 IndicSyllable *syllables = NULL;
2772 int syllable_count = 0;
2773 BOOL modern = get_GSUB_Indic2(psa, psc);
2775 if (*pcGlyphs != cChars)
2777 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2778 return;
2781 input = heap_alloc(2 * cChars * sizeof(*input));
2782 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2784 /* Step 1: Decompose Vowels */
2785 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2786 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2788 /* Step 2: Reorder within Syllables */
2789 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2790 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2791 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2792 *pcGlyphs = cCount;
2794 /* Step 3: Base Form application to syllables */
2795 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2797 heap_free(input);
2798 heap_free(syllables);
2801 static int khmer_lex(WCHAR c)
2803 return unicode_lex(c);
2806 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2808 int cCount = cChars;
2809 WCHAR *input;
2810 IndicSyllable *syllables = NULL;
2811 int syllable_count = 0;
2813 if (*pcGlyphs != cChars)
2815 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2816 return;
2819 input = heap_alloc(cChars * sizeof(*input));
2820 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2822 /* Step 1: Reorder within Syllables */
2823 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2824 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2825 NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2826 *pcGlyphs = cCount;
2828 /* Step 2: Base Form application to syllables */
2829 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2831 heap_free(input);
2832 heap_free(syllables);
2835 static inline BOOL mongolian_wordbreak(WCHAR chr)
2837 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2840 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2842 INT *context_shape;
2843 INT dirL;
2844 int i;
2845 int char_index;
2846 int glyph_index;
2848 if (*pcGlyphs != cChars)
2850 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2851 return;
2854 if (!psa->fLogicalOrder && psa->fRTL)
2855 dirL = -1;
2856 else
2857 dirL = 1;
2859 if (!psc->GSUB_Table)
2860 return;
2862 context_shape = heap_alloc(cChars * sizeof(*context_shape));
2864 for (i = 0; i < cChars; i++)
2866 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2868 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2869 context_shape[i] = Xn;
2870 else
2871 context_shape[i] = Xl;
2873 else
2875 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2876 context_shape[i] = Xr;
2877 else
2878 context_shape[i] = Xm;
2882 /* Contextual Shaping */
2883 if (dirL > 0)
2884 char_index = glyph_index = 0;
2885 else
2886 char_index = glyph_index = cChars-1;
2888 while(char_index < cChars && char_index >= 0)
2890 INT nextIndex;
2891 INT prevCount = *pcGlyphs;
2892 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2894 if (nextIndex > GSUB_E_NOGLYPH)
2896 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2897 glyph_index = nextIndex;
2898 char_index += dirL;
2900 else
2902 char_index += dirL;
2903 glyph_index += dirL;
2907 heap_free(context_shape);
2910 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)
2912 int i,k;
2914 for (i = 0; i < cGlyphs; i++)
2916 int char_index[20];
2917 int char_count = 0;
2919 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2920 if (k>=0)
2922 for (; k < cChars && pwLogClust[k] == i; k++)
2923 char_index[char_count++] = k;
2926 if (char_count == 0)
2927 continue;
2929 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2931 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2932 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2934 else
2935 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2938 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2939 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2942 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 )
2944 int i;
2946 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2948 for (i = 0; i < cGlyphs; i++)
2949 if (pGlyphProp[i].sva.fZeroWidth)
2950 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2953 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 )
2955 int i;
2956 for (i = 0; i < cGlyphs; i++)
2958 pGlyphProp[i].sva.fClusterStart = 1;
2959 pGlyphProp[i].sva.fDiacritic = 0;
2960 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2962 if (pwGlyphs[i] == psc->sfp.wgDefault)
2963 pGlyphProp[i].sva.fZeroWidth = 0;
2964 else
2965 pGlyphProp[i].sva.fZeroWidth = 1;
2969 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 )
2971 int i,k;
2972 int initGlyph, finaGlyph;
2973 INT dirR, dirL;
2974 BYTE *spaces;
2976 spaces = heap_alloc(cGlyphs);
2977 memset(spaces,0,cGlyphs);
2979 if (psa->fLogicalOrder && psa->fRTL)
2981 initGlyph = 0;
2982 finaGlyph = cGlyphs-1;
2983 dirR = -1;
2984 dirL = 1;
2986 else
2988 initGlyph = cGlyphs-1;
2989 finaGlyph = 0;
2990 dirR = 1;
2991 dirL = -1;
2994 for (i = 0; i < cGlyphs; i++)
2996 for (k = 0; k < cChars; k++)
2997 if (pwLogClust[k] == i)
2999 if (pwcChars[k] == 0x0020)
3000 spaces[i] = 1;
3004 for (i = 0; i < cGlyphs; i++)
3006 int char_index[20];
3007 int char_count = 0;
3008 BOOL isInit, isFinal;
3010 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3011 if (k>=0)
3013 for (; k < cChars && pwLogClust[k] == i; k++)
3014 char_index[char_count++] = k;
3017 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3018 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3020 if (char_count == 0)
3021 continue;
3023 if (char_count == 1)
3025 if (pwcChars[char_index[0]] == 0x0020) /* space */
3027 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3028 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3030 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3031 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3032 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3034 if (!isInit && !isFinal)
3035 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3036 else if (isInit)
3037 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3038 else
3039 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3041 else if (!isInit)
3043 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3044 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3045 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3046 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3047 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3048 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3049 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3050 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3051 else
3052 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3054 else if (!isInit && !isFinal)
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3056 else
3057 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3059 else if (char_count == 2)
3061 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3062 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3063 else if (!isInit)
3064 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3065 else
3066 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3068 else if (!isInit && !isFinal)
3069 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3070 else
3071 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3074 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3075 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3076 heap_free(spaces);
3079 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 )
3081 int i,k;
3083 for (i = 0; i < cGlyphs; i++)
3085 int char_index[20];
3086 int char_count = 0;
3088 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3089 if (k>=0)
3091 for (; k < cChars && pwLogClust[k] == i; k++)
3092 char_index[char_count++] = k;
3095 if (char_count == 0)
3096 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3097 else
3099 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3100 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3101 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3105 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3106 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3109 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 )
3111 int i;
3112 int finaGlyph;
3113 INT dirL;
3115 if (!psa->fLogicalOrder && psa->fRTL)
3117 finaGlyph = 0;
3118 dirL = -1;
3120 else
3122 finaGlyph = cGlyphs-1;
3123 dirL = 1;
3126 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3128 for (i = 0; i < cGlyphs; i++)
3130 int k;
3131 int char_index[20];
3132 int char_count = 0;
3134 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3135 if (k>=0)
3137 for (; k < cChars && pwLogClust[k] == i; k++)
3138 char_index[char_count++] = k;
3141 if (i == finaGlyph)
3142 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3143 else
3144 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3146 if (char_count == 0)
3147 continue;
3149 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3150 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3152 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3153 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3154 pGlyphProp[i].sva.fClusterStart = 0;
3157 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3159 /* Do not allow justification between marks and their base */
3160 for (i = 0; i < cGlyphs; i++)
3162 if (!pGlyphProp[i].sva.fClusterStart)
3163 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3167 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)
3169 int i,k;
3171 for (i = 0; i < cGlyphs; i++)
3173 int char_index[20];
3174 int char_count = 0;
3176 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3177 if (k>=0)
3179 for (; k < cChars && pwLogClust[k] == i; k++)
3180 char_index[char_count++] = k;
3183 if (char_count == 0)
3184 continue;
3186 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3188 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3189 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3191 else
3192 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3194 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3195 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3198 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)
3200 int i,k;
3202 for (i = 0; i < cGlyphs; i++)
3204 int char_index[20];
3205 int char_count = 0;
3207 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3208 if (k>=0)
3210 for (; k < cChars && pwLogClust[k] == i; k++)
3211 char_index[char_count++] = k;
3214 if (char_count == 0)
3215 continue;
3217 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3219 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3220 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3222 else
3223 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3225 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3226 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3228 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3229 for (i = 0; i < cGlyphs; i++)
3231 if (!pGlyphProp[i].sva.fClusterStart)
3233 pGlyphProp[i].sva.fDiacritic = 0;
3234 pGlyphProp[i].sva.fZeroWidth = 0;
3239 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)
3241 int i,k;
3243 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3244 for (i = 0; i < cGlyphs; i++)
3246 int char_index[20];
3247 int char_count = 0;
3249 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3250 if (k>=0)
3252 for (; k < cChars && pwLogClust[k] == i; k++)
3253 char_index[char_count++] = k;
3256 if (override_gsub)
3258 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3259 pGlyphProp[i].sva.fDiacritic = FALSE;
3260 pGlyphProp[i].sva.fZeroWidth = FALSE;
3263 if (char_count == 0)
3265 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3266 continue;
3269 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3271 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3272 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3274 else
3275 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3277 pGlyphProp[i].sva.fClusterStart = 0;
3278 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3279 switch (lexical(pwcChars[char_index[k]]))
3281 case lex_Matra_pre:
3282 case lex_Matra_post:
3283 case lex_Matra_above:
3284 case lex_Matra_below:
3285 case lex_Modifier:
3286 case lex_Halant:
3287 break;
3288 case lex_ZWJ:
3289 case lex_ZWNJ:
3290 /* check for dangling joiners */
3291 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3292 pGlyphProp[i].sva.fClusterStart = 1;
3293 else
3294 k = char_count;
3295 break;
3296 default:
3297 pGlyphProp[i].sva.fClusterStart = 1;
3298 break;
3302 if (use_syllables)
3304 IndicSyllable *syllables = NULL;
3305 int syllable_count = 0;
3306 BOOL modern = get_GSUB_Indic2(psa, psc);
3308 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3310 for (i = 0; i < syllable_count; i++)
3312 int j;
3313 WORD g = pwLogClust[syllables[i].start];
3314 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3316 if (pwLogClust[j] != g)
3318 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3319 pwLogClust[j] = g;
3324 heap_free(syllables);
3327 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3330 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 )
3332 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3335 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 )
3337 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3340 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 )
3342 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3345 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 )
3347 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3350 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 )
3352 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3355 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 )
3357 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3360 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 )
3362 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3365 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 )
3367 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3370 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 )
3372 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3375 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 )
3377 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3380 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 )
3382 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3385 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)
3387 load_ot_tables(hdc, psc);
3389 if (ShapingData[psa->eScript].charGlyphPropProc)
3390 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3391 else
3392 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3395 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3397 load_ot_tables(hdc, psc);
3399 if (ShapingData[psa->eScript].contextProc)
3400 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3403 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)
3405 int i;
3406 INT dirL;
3408 if (!rpRangeProperties)
3409 return;
3411 load_ot_tables(hdc, psc);
3413 if (!psc->GSUB_Table)
3414 return;
3416 if (scriptInformation[psa->eScript].a.fRTL && (!psa->fLogicalOrder || !psa->fRTL))
3417 dirL = -1;
3418 else
3419 dirL = 1;
3421 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3423 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3424 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3428 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3430 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3431 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3433 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3436 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3438 const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3439 int i;
3441 load_ot_tables(hdc, psc);
3443 if (!psc->GPOS_Table || !psc->otm)
3444 return;
3446 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3448 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3450 LoadedFeature *feature;
3452 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3453 if (!feature)
3454 continue;
3456 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3461 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3463 LoadedFeature *feature;
3464 int i;
3466 if (!ShapingData[psa->eScript].requiredFeatures)
3467 return S_OK;
3469 load_ot_tables(hdc, psc);
3471 /* we need to have at least one of the required features */
3472 i = 0;
3473 while (ShapingData[psa->eScript].requiredFeatures[i])
3475 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3476 if (feature)
3477 return S_OK;
3478 i++;
3481 return USP_E_SCRIPT_NOT_IN_FONT;
3484 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3485 SCRIPT_ANALYSIS *psa, int cMaxTags,
3486 OPENTYPE_TAG *pScriptTags, int *pcTags)
3488 HRESULT hr;
3489 OPENTYPE_TAG searching = 0x00000000;
3491 load_ot_tables(hdc, psc);
3493 if (psa && scriptInformation[psa->eScript].scriptTag)
3494 searching = scriptInformation[psa->eScript].scriptTag;
3496 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3497 if (FAILED(hr))
3498 *pcTags = 0;
3499 return hr;
3502 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3503 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3504 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3505 int *pcTags)
3507 HRESULT hr;
3508 OPENTYPE_TAG searching = 0x00000000;
3509 BOOL fellback = FALSE;
3511 load_ot_tables(hdc, psc);
3513 if (psa && psc->userLang != 0)
3514 searching = psc->userLang;
3516 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3517 if (FAILED(hr))
3519 fellback = TRUE;
3520 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3523 if (FAILED(hr) || fellback)
3524 *pcTags = 0;
3525 if (SUCCEEDED(hr) && fellback && psa)
3526 hr = E_INVALIDARG;
3527 return hr;
3530 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3531 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3532 OPENTYPE_TAG tagLangSys, int cMaxTags,
3533 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3535 HRESULT hr;
3536 BOOL filter = FALSE;
3538 load_ot_tables(hdc, psc);
3540 if (psa && scriptInformation[psa->eScript].scriptTag)
3542 FIXME("Filtering not implemented\n");
3543 filter = TRUE;
3546 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3548 if (FAILED(hr))
3549 *pcTags = 0;
3550 return hr;