usp10: Fall back to 'dflt' language if shaping language tag isn't found.
[wine.git] / dlls / usp10 / shape.c
blobb75be601dbd0d11716bbb494db25b307d60298de
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #define FIRST_ARABIC_CHAR 0x0600
39 #define LAST_ARABIC_CHAR 0x06ff
41 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
42 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
63 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
65 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
67 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
68 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
73 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
75 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
76 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
77 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
78 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
79 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
80 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
81 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
82 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
83 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
84 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
85 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
87 extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
88 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
89 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
91 enum joining_types {
92 jtU,
93 jtT,
94 jtR,
95 jtL,
96 jtD,
97 jtC
100 enum joined_forms {
101 Xn=0,
105 /* Syriac Alaph */
106 Afj,
107 Afn,
111 typedef struct tagVowelComponents
113 WCHAR base;
114 WCHAR parts[3];
115 } VowelComponents;
117 typedef struct tagConsonantComponents
119 WCHAR parts[3];
120 WCHAR output;
121 } ConsonantComponents;
123 typedef void (*second_reorder_function)(const WCHAR *chars, const IndicSyllable *syllable,
124 WORD *glyphs, const IndicSyllable *glyph_index, lexical_function lex);
126 typedef int (*combining_lexical_function)(WCHAR c);
128 /* the orders of joined_forms and contextual_features need to line up */
129 static const char *const contextual_features[] =
131 "isol",
132 "fina",
133 "init",
134 "medi",
135 /* Syriac Alaph */
136 "med2",
137 "fin2",
138 "fin3"
141 static OPENTYPE_FEATURE_RECORD standard_features[] =
143 { MS_MAKE_TAG('c','c','m','p'), 1},
144 { MS_MAKE_TAG('l','o','c','l'), 1},
147 static OPENTYPE_FEATURE_RECORD latin_features[] =
149 { MS_MAKE_TAG('l','o','c','l'), 1},
150 { MS_MAKE_TAG('c','c','m','p'), 1},
151 { MS_MAKE_TAG('l','i','g','a'), 1},
152 { MS_MAKE_TAG('c','l','i','g'), 1},
155 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
157 { MS_MAKE_TAG('k','e','r','n'), 1},
158 { MS_MAKE_TAG('m','a','r','k'), 1},
159 { MS_MAKE_TAG('m','k','m','k'), 1},
162 static OPENTYPE_FEATURE_RECORD arabic_features[] =
164 { MS_MAKE_TAG('r','l','i','g'), 1},
165 { MS_MAKE_TAG('c','a','l','t'), 1},
166 { MS_MAKE_TAG('l','i','g','a'), 1},
167 { MS_MAKE_TAG('d','l','i','g'), 1},
168 { MS_MAKE_TAG('c','s','w','h'), 1},
169 { MS_MAKE_TAG('m','s','e','t'), 1},
172 static const char *const required_arabic_features[] =
174 "fina",
175 "init",
176 "medi",
177 "rlig",
178 NULL
181 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
183 { MS_MAKE_TAG('c','u','r','s'), 1},
184 { MS_MAKE_TAG('k','e','r','n'), 1},
185 { MS_MAKE_TAG('m','a','r','k'), 1},
186 { MS_MAKE_TAG('m','k','m','k'), 1},
189 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
191 { MS_MAKE_TAG('c','c','m','p'), 1},
192 { MS_MAKE_TAG('d','l','i','g'), 0},
195 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
197 { MS_MAKE_TAG('k','e','r','n'), 1},
198 { MS_MAKE_TAG('m','a','r','k'), 1},
201 static OPENTYPE_FEATURE_RECORD syriac_features[] =
203 { MS_MAKE_TAG('r','l','i','g'), 1},
204 { MS_MAKE_TAG('c','a','l','t'), 1},
205 { MS_MAKE_TAG('l','i','g','a'), 1},
206 { MS_MAKE_TAG('d','l','i','g'), 1},
209 static const char *const required_syriac_features[] =
211 "fina",
212 "fin2",
213 "fin3",
214 "init",
215 "medi",
216 "med2",
217 "rlig",
218 NULL
221 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
223 { MS_MAKE_TAG('k','e','r','n'), 1},
224 { MS_MAKE_TAG('m','a','r','k'), 1},
225 { MS_MAKE_TAG('m','k','m','k'), 1},
228 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
230 /* Presentation forms */
231 { MS_MAKE_TAG('b','l','w','s'), 1},
232 { MS_MAKE_TAG('a','b','v','s'), 1},
233 { MS_MAKE_TAG('p','s','t','s'), 1},
236 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
238 { MS_MAKE_TAG('a','b','v','s'), 1},
239 { MS_MAKE_TAG('b','l','w','s'), 1},
242 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
244 { MS_MAKE_TAG('a','b','v','m'), 1},
245 { MS_MAKE_TAG('b','l','w','m'), 1},
248 static OPENTYPE_FEATURE_RECORD phags_features[] =
250 { MS_MAKE_TAG('a','b','v','s'), 1},
251 { MS_MAKE_TAG('b','l','w','s'), 1},
252 { MS_MAKE_TAG('c','a','l','t'), 1},
255 static OPENTYPE_FEATURE_RECORD thai_features[] =
257 { MS_MAKE_TAG('c','c','m','p'), 1},
260 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
262 { MS_MAKE_TAG('k','e','r','n'), 1},
263 { MS_MAKE_TAG('m','a','r','k'), 1},
264 { MS_MAKE_TAG('m','k','m','k'), 1},
267 static const char *const required_lao_features[] =
269 "ccmp",
270 NULL
273 static const char *const required_devanagari_features[] =
275 "nukt",
276 "akhn",
277 "rphf",
278 "blwf",
279 "half",
280 "vatu",
281 "pres",
282 "abvs",
283 "blws",
284 "psts",
285 "haln",
286 NULL
289 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
291 { MS_MAKE_TAG('p','r','e','s'), 1},
292 { MS_MAKE_TAG('a','b','v','s'), 1},
293 { MS_MAKE_TAG('b','l','w','s'), 1},
294 { MS_MAKE_TAG('p','s','t','s'), 1},
295 { MS_MAKE_TAG('h','a','l','n'), 1},
296 { MS_MAKE_TAG('c','a','l','t'), 1},
299 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
301 { MS_MAKE_TAG('k','e','r','n'), 1},
302 { MS_MAKE_TAG('d','i','s','t'), 1},
303 { MS_MAKE_TAG('a','b','v','m'), 1},
304 { MS_MAKE_TAG('b','l','w','m'), 1},
307 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
309 { MS_MAKE_TAG('l','i','g','a'), 1},
310 { MS_MAKE_TAG('c','l','i','g'), 1},
313 static const char *const required_bengali_features[] =
315 "nukt",
316 "akhn",
317 "rphf",
318 "blwf",
319 "half",
320 "vatu",
321 "pstf",
322 "init",
323 "abvs",
324 "blws",
325 "psts",
326 "haln",
327 NULL
330 static const char *const required_gurmukhi_features[] =
332 "nukt",
333 "akhn",
334 "rphf",
335 "blwf",
336 "half",
337 "pstf",
338 "vatu",
339 "cjct",
340 "pres",
341 "abvs",
342 "blws",
343 "psts",
344 "haln",
345 "calt",
346 NULL
349 static const char *const required_oriya_features[] =
351 "nukt",
352 "akhn",
353 "rphf",
354 "blwf",
355 "pstf",
356 "cjct",
357 "pres",
358 "abvs",
359 "blws",
360 "psts",
361 "haln",
362 "calt",
363 NULL
366 static const char *const required_tamil_features[] =
368 "nukt",
369 "akhn",
370 "rphf",
371 "pref",
372 "half",
373 "pres",
374 "abvs",
375 "blws",
376 "psts",
377 "haln",
378 "calt",
379 NULL
382 static const char *const required_telugu_features[] =
384 "nukt",
385 "akhn",
386 "rphf",
387 "pref",
388 "half",
389 "pstf",
390 "cjct",
391 "pres",
392 "abvs",
393 "blws",
394 "psts",
395 "haln",
396 "calt",
397 NULL
400 static OPENTYPE_FEATURE_RECORD khmer_features[] =
402 { MS_MAKE_TAG('p','r','e','s'), 1},
403 { MS_MAKE_TAG('b','l','w','s'), 1},
404 { MS_MAKE_TAG('a','b','v','s'), 1},
405 { MS_MAKE_TAG('p','s','t','s'), 1},
406 { MS_MAKE_TAG('c','l','i','g'), 1},
409 static const char *const required_khmer_features[] =
411 "pref",
412 "blwf",
413 "abvf",
414 "pstf",
415 "pres",
416 "blws",
417 "abvs",
418 "psts",
419 "clig",
420 NULL
423 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
425 { MS_MAKE_TAG('d','i','s','t'), 1},
426 { MS_MAKE_TAG('b','l','w','m'), 1},
427 { MS_MAKE_TAG('a','b','v','m'), 1},
428 { MS_MAKE_TAG('m','k','m','k'), 1},
431 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
433 { MS_MAKE_TAG('c','c','m','p'), 1},
434 { MS_MAKE_TAG('l','o','c','l'), 1},
435 { MS_MAKE_TAG('c','a','l','t'), 1},
436 { MS_MAKE_TAG('l','i','g','a'), 1},
439 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
441 { MS_MAKE_TAG('c','c','m','p'), 1},
442 { MS_MAKE_TAG('l','o','c','l'), 1},
443 { MS_MAKE_TAG('c','a','l','t'), 1},
444 { MS_MAKE_TAG('r','l','i','g'), 1},
447 typedef struct ScriptShapeDataTag {
448 TEXTRANGE_PROPERTIES defaultTextRange;
449 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
450 const char *const *requiredFeatures;
451 OPENTYPE_TAG newOtTag;
452 ContextualShapingProc contextProc;
453 ShapeCharGlyphPropProc charGlyphPropProc;
454 } ScriptShapeData;
456 /* in order of scripts */
457 static const ScriptShapeData ShapingData[] =
459 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
460 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
461 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
462 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
463 {{ standard_features, 2}, {NULL, 0}, NULL, 0, ContextualShape_Control, ShapeCharGlyphProp_Control},
464 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
465 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
466 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
467 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
468 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
469 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
470 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
471 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
472 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
473 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
474 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
475 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
476 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
477 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
478 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
479 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
480 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
481 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
482 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
483 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
497 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
498 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
499 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
500 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
501 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
502 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
503 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
504 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
505 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
506 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
511 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
512 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
513 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
516 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
522 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
523 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
524 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
526 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
527 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
528 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
529 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
530 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
531 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
532 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
533 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
534 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
535 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
536 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
537 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
538 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
539 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
540 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
543 extern scriptData scriptInformation[];
545 static int GSUB_apply_feature_all_lookups(const void *header, LoadedFeature *feature,
546 WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count)
548 int i;
549 int out_index = GSUB_E_NOGLYPH;
551 TRACE("%i lookups\n", feature->lookup_count);
552 for (i = 0; i < feature->lookup_count; i++)
554 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
555 if (out_index != GSUB_E_NOGLYPH)
556 break;
558 if (out_index == GSUB_E_NOGLYPH)
559 TRACE("lookups found no glyphs\n");
560 else
562 int out2;
563 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
564 if (out2!=GSUB_E_NOGLYPH)
565 out_index = out2;
567 return out_index;
570 static OPENTYPE_TAG get_opentype_script(HDC hdc, const SCRIPT_ANALYSIS *psa,
571 const ScriptCache *script_cache, BOOL try_new)
573 UINT charset;
575 if (script_cache->userScript)
577 if (try_new && ShapingData[psa->eScript].newOtTag
578 && script_cache->userScript == scriptInformation[psa->eScript].scriptTag)
579 return ShapingData[psa->eScript].newOtTag;
581 return script_cache->userScript;
584 if (try_new && ShapingData[psa->eScript].newOtTag)
585 return ShapingData[psa->eScript].newOtTag;
587 if (scriptInformation[psa->eScript].scriptTag)
588 return scriptInformation[psa->eScript].scriptTag;
591 * fall back to the font charset
593 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
594 switch (charset)
596 case ANSI_CHARSET:
597 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
598 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
599 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
600 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
601 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
602 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
603 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
604 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
605 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
606 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
607 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
608 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
609 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
610 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
611 default: return MS_MAKE_TAG('l','a','t','n');
615 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
617 LoadedFeature *feature = NULL;
619 if (psc->GSUB_Table || psc->GPOS_Table)
621 int attempt = 2;
622 OPENTYPE_TAG tags;
623 OPENTYPE_TAG language;
624 OPENTYPE_TAG script = 0x00000000;
625 int cTags;
629 script = get_opentype_script(hdc,psa,psc,(attempt==2));
630 if (psc->userLang != 0)
631 language = psc->userLang;
632 else
633 language = MS_MAKE_TAG('d','f','l','t');
634 attempt--;
636 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
638 } while(attempt && !feature);
640 /* try in the default (latin) table */
641 if (!feature)
643 if (!script)
644 script = MS_MAKE_TAG('l','a','t','n');
645 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);
649 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
650 return feature;
653 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)
655 LoadedFeature *feature;
657 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
658 if (!feature)
659 return GSUB_E_NOFEATURE;
661 TRACE("applying feature %s\n",feat);
662 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
665 static VOID *load_gsub_table(HDC hdc)
667 VOID* GSUB_Table = NULL;
668 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
669 if (length != GDI_ERROR)
671 GSUB_Table = heap_alloc(length);
672 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
673 TRACE("Loaded GSUB table of %i bytes\n",length);
675 return GSUB_Table;
678 static VOID *load_gpos_table(HDC hdc)
680 VOID* GPOS_Table = NULL;
681 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
682 if (length != GDI_ERROR)
684 GPOS_Table = heap_alloc(length);
685 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
686 TRACE("Loaded GPOS table of %i bytes\n",length);
688 return GPOS_Table;
691 static VOID *load_gdef_table(HDC hdc)
693 VOID* GDEF_Table = NULL;
694 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
695 if (length != GDI_ERROR)
697 GDEF_Table = heap_alloc(length);
698 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
699 TRACE("Loaded GDEF table of %i bytes\n",length);
701 return GDEF_Table;
704 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
706 if (!psc->GSUB_Table)
707 psc->GSUB_Table = load_gsub_table(hdc);
708 if (!psc->GPOS_Table)
709 psc->GPOS_Table = load_gpos_table(hdc);
710 if (!psc->GDEF_Table)
711 psc->GDEF_Table = load_gdef_table(hdc);
714 INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature)
716 WORD *glyphs;
717 INT glyph_count = count;
718 INT rc;
720 glyphs = heap_alloc(2 * count * sizeof(*glyphs));
721 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
722 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
723 if (rc > GSUB_E_NOGLYPH)
724 rc = count - glyph_count;
725 else
726 rc = 0;
728 heap_free(glyphs);
729 return rc;
732 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
734 int i;
736 for (i = 0; i < cGlyphs; i++)
738 if (!pGlyphProp[i].sva.fClusterStart)
740 int j;
741 for (j = 0; j < cChars; j++)
743 if (pwLogClust[j] == i)
745 int k = j;
746 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
747 k-=1;
748 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
749 pwLogClust[j] = pwLogClust[k];
756 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
758 if (changeCount == 0)
759 return;
760 else
762 int cluster_dir = pwLogClust[0] < pwLogClust[chars-1] ? 1 : -1;
763 int i;
764 int target_glyph = nextIndex - write_dir;
765 int target_index = -1;
766 int replacing_glyph = -1;
767 int changed = 0;
769 if (changeCount > 0)
771 if (write_dir > 0)
772 target_glyph = nextIndex - changeCount;
773 else
774 target_glyph = nextIndex + (changeCount + 1);
777 target_index = USP10_FindGlyphInLogClust(pwLogClust, chars, target_glyph);
778 if (target_index == -1)
780 ERR("Unable to find target glyph\n");
781 return;
784 if (changeCount < 0)
786 /* merge glyphs */
787 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
789 if (pwLogClust[i] == target_glyph)
790 continue;
791 if(pwLogClust[i] == replacing_glyph)
792 pwLogClust[i] = target_glyph;
793 else
795 changed--;
796 if (changed >= changeCount)
798 replacing_glyph = pwLogClust[i];
799 pwLogClust[i] = target_glyph;
801 else
802 break;
806 /* renumber trailing indexes */
807 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
809 if (pwLogClust[i] != target_glyph)
810 pwLogClust[i] += changeCount;
813 else
815 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
816 pwLogClust[i] += changeCount;
821 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 )
823 if (psc->GSUB_Table)
825 LoadedFeature *feature;
826 int lookup_index;
828 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
829 if (!feature)
830 return GSUB_E_NOFEATURE;
832 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
833 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
835 int i;
837 if (write_dir > 0)
838 i = 0;
839 else
840 i = *pcGlyphs-1;
841 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
842 while(i < *pcGlyphs && i >= 0)
844 INT nextIndex;
845 INT prevCount = *pcGlyphs;
847 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
848 if (*pcGlyphs != prevCount)
850 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
851 i = nextIndex;
853 else
854 i+=write_dir;
857 return *pcGlyphs;
859 return GSUB_E_NOFEATURE;
862 static void GPOS_apply_feature(const ScriptCache *psc, const OUTLINETEXTMETRICW *otm,
863 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance,
864 const LoadedFeature *feature, const WORD *glyphs, int glyph_count, GOFFSET *goffset)
866 int dir = analysis->fLogicalOrder && analysis->fRTL ? -1 : 1;
867 unsigned int start_idx, i, j;
869 TRACE("%i lookups\n", feature->lookup_count);
871 start_idx = dir < 0 ? glyph_count - 1 : 0;
872 for (i = 0; i < feature->lookup_count; i++)
874 for (j = 0; j < glyph_count; )
875 j += OpenType_apply_GPOS_lookup(psc, otm, logfont, analysis, advance,
876 feature->lookups[i], glyphs, start_idx + dir * j, glyph_count, goffset);
880 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
882 OPENTYPE_TAG tag;
883 HRESULT hr;
884 int count = 0;
886 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
888 return(SUCCEEDED(hr));
891 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
893 int i;
894 for (i = *pcGlyphs; i>=index; i--)
895 pwGlyphs[i+1] = pwGlyphs[i];
896 pwGlyphs[index] = glyph;
897 *pcGlyphs = *pcGlyphs+1;
898 if (write_dir < 0)
899 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
900 else
901 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
904 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)
906 CHAR *context_type;
907 int i,g;
908 WCHAR invalid = 0x25cc;
909 WORD invalid_glyph;
911 context_type = heap_alloc(cChars);
913 /* Mark invalid combinations */
914 for (i = 0; i < cChars; i++)
915 context_type[i] = lex(pwcChars[i]);
917 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
918 for (i = 1, g=1; i < cChars - 1; i++, g++)
920 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
922 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
923 g++;
927 heap_free(context_type);
930 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
932 int i;
933 for (i=0; i < cChars; i++)
935 switch (pwcChars[i])
937 case 0x000A:
938 case 0x000D:
939 pwOutGlyphs[i] = psc->sfp.wgBlank;
940 break;
941 default:
942 if (pwcChars[i] < 0x1C)
943 pwOutGlyphs[i] = psc->sfp.wgDefault;
944 else
945 pwOutGlyphs[i] = psc->sfp.wgBlank;
950 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
952 if (i + delta < 0)
953 return 0;
954 if ( i+ delta >= cchLen)
955 return 0;
957 i += delta;
959 return chars[i];
962 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
964 if (i + delta < 0)
966 if (psa->fLinkBefore)
967 return jtR;
968 else
969 return jtU;
971 if ( i+ delta >= cchLen)
973 if (psa->fLinkAfter)
974 return jtL;
975 else
976 return jtU;
979 i += delta;
981 if (context_type[i] == jtT)
982 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
983 else
984 return context_type[i];
987 static inline BOOL right_join_causing(CHAR joining_type)
989 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
992 static inline BOOL left_join_causing(CHAR joining_type)
994 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
997 static inline BOOL word_break_causing(WCHAR chr)
999 /* we are working within a string of characters already guareented to
1000 be within one script, Syriac, so we do not worry about any character
1001 other than the space character outside of that range */
1002 return (chr == 0 || chr == 0x20 );
1005 static int combining_lexical_Arabic(WCHAR c)
1007 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1009 switch(c)
1011 case 0x064B:
1012 case 0x064C:
1013 case 0x064E:
1014 case 0x064F:
1015 case 0x0652:
1016 case 0x0657:
1017 case 0x0658:
1018 case 0x06E1: return Arab_DIAC1;
1019 case 0x064D:
1020 case 0x0650:
1021 case 0x0656: return Arab_DIAC2;
1022 case 0x0651: return Arab_DIAC3;
1023 case 0x0610:
1024 case 0x0611:
1025 case 0x0612:
1026 case 0x0613:
1027 case 0x0614:
1028 case 0x0659:
1029 case 0x06D6:
1030 case 0x06DC:
1031 case 0x06DF:
1032 case 0x06E0:
1033 case 0x06E2:
1034 case 0x06E4:
1035 case 0x06E7:
1036 case 0x06E8:
1037 case 0x06EB:
1038 case 0x06EC: return Arab_DIAC4;
1039 case 0x06E3:
1040 case 0x06EA:
1041 case 0x06ED: return Arab_DIAC5;
1042 case 0x0670: return Arab_DIAC6;
1043 case 0x0653: return Arab_DIAC7;
1044 case 0x0655:
1045 case 0x0654: return Arab_DIAC8;
1046 default: return Arab_Norm;
1051 * ContextualShape_Arabic
1053 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1055 CHAR *context_type;
1056 INT *context_shape;
1057 INT dirR, dirL;
1058 int i;
1059 int char_index;
1060 int glyph_index;
1062 if (*pcGlyphs != cChars)
1064 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1065 return;
1068 if (psa->fLogicalOrder && psa->fRTL)
1070 dirR = -1;
1071 dirL = 1;
1073 else
1075 dirR = 1;
1076 dirL = -1;
1079 load_ot_tables(hdc, psc);
1081 context_type = heap_alloc(cChars);
1082 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1084 for (i = 0; i < cChars; i++)
1085 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1087 for (i = 0; i < cChars; i++)
1089 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1090 context_shape[i] = Xr;
1091 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1092 context_shape[i] = Xl;
1093 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)))
1094 context_shape[i] = Xm;
1095 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1096 context_shape[i] = Xr;
1097 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1098 context_shape[i] = Xl;
1099 else
1100 context_shape[i] = Xn;
1103 /* Contextual Shaping */
1104 if (dirL > 0)
1105 char_index = glyph_index = 0;
1106 else
1107 char_index = glyph_index = cChars-1;
1109 while(char_index < cChars && char_index >= 0)
1111 BOOL shaped = FALSE;
1113 if (psc->GSUB_Table)
1115 INT nextIndex, offset = 0;
1116 INT prevCount = *pcGlyphs;
1118 /* Apply CCMP first */
1119 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1121 if (prevCount != *pcGlyphs)
1123 offset = *pcGlyphs - prevCount;
1124 if (dirL < 0)
1125 glyph_index -= offset * dirL;
1128 /* Apply the contextual feature */
1129 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1131 if (nextIndex > GSUB_E_NOGLYPH)
1133 UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1134 char_index += dirL;
1135 if (!offset)
1136 glyph_index = nextIndex;
1137 else
1139 offset = *pcGlyphs - prevCount;
1140 glyph_index += dirL * (offset + 1);
1142 shaped = TRUE;
1144 else if (nextIndex == GSUB_E_NOGLYPH)
1146 char_index += dirL;
1147 glyph_index += dirL;
1148 shaped = TRUE;
1152 if (!shaped)
1154 if (context_shape[char_index] == Xn)
1156 WORD newGlyph = pwOutGlyphs[glyph_index];
1157 if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
1159 /* fall back to presentation form B */
1160 WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
1161 if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1162 pwOutGlyphs[glyph_index] = newGlyph;
1165 char_index += dirL;
1166 glyph_index += dirL;
1170 heap_free(context_shape);
1171 heap_free(context_type);
1173 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1176 static int combining_lexical_Hebrew(WCHAR c)
1178 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};
1180 switch(c)
1182 case 0x05B0:
1183 case 0x05B1:
1184 case 0x05B2:
1185 case 0x05B3:
1186 case 0x05B4:
1187 case 0x05B5:
1188 case 0x05B6:
1189 case 0x05BB: return Hebr_DIAC;
1190 case 0x0599:
1191 case 0x05A1:
1192 case 0x05A9:
1193 case 0x05AE: return Hebr_CANT1;
1194 case 0x0597:
1195 case 0x05A8:
1196 case 0x05AC: return Hebr_CANT2;
1197 case 0x0592:
1198 case 0x0593:
1199 case 0x0594:
1200 case 0x0595:
1201 case 0x05A7:
1202 case 0x05AB: return Hebr_CANT3;
1203 case 0x0598:
1204 case 0x059C:
1205 case 0x059E:
1206 case 0x059F: return Hebr_CANT4;
1207 case 0x059D:
1208 case 0x05A0: return Hebr_CANT5;
1209 case 0x059B:
1210 case 0x05A5: return Hebr_CANT6;
1211 case 0x0591:
1212 case 0x05A3:
1213 case 0x05A6: return Hebr_CANT7;
1214 case 0x0596:
1215 case 0x05A4:
1216 case 0x05AA: return Hebr_CANT8;
1217 case 0x059A:
1218 case 0x05AD: return Hebr_CANT9;
1219 case 0x05AF: return Hebr_CANT10;
1220 case 0x05BC: return Hebr_DAGESH;
1221 case 0x05C4: return Hebr_DOTABV;
1222 case 0x05B9: return Hebr_HOLAM;
1223 case 0x05BD: return Hebr_METEG;
1224 case 0x05B7: return Hebr_PATAH;
1225 case 0x05B8: return Hebr_QAMATS;
1226 case 0x05BF: return Hebr_RAFE;
1227 case 0x05C1:
1228 case 0x05C2: return Hebr_SHINSIN;
1229 default: return Hebr_Norm;
1233 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1235 INT dirL;
1237 if (*pcGlyphs != cChars)
1239 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1240 return;
1243 if (!psa->fLogicalOrder && psa->fRTL)
1244 dirL = -1;
1245 else
1246 dirL = 1;
1248 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1252 * ContextualShape_Syriac
1255 static int combining_lexical_Syriac(WCHAR c)
1257 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};
1259 switch(c)
1261 case 0x730:
1262 case 0x733:
1263 case 0x736:
1264 case 0x73A:
1265 case 0x73D: return Syriac_DIAC1;
1266 case 0x731:
1267 case 0x734:
1268 case 0x737:
1269 case 0x73B:
1270 case 0x73E: return Syriac_DIAC2;
1271 case 0x740:
1272 case 0x749:
1273 case 0x74A: return Syriac_DIAC3;
1274 case 0x732:
1275 case 0x735:
1276 case 0x73F: return Syriac_DIAC4;
1277 case 0x738:
1278 case 0x739:
1279 case 0x73C: return Syriac_DIAC5;
1280 case 0x741:
1281 case 0x30A: return Syriac_DIAC6;
1282 case 0x742:
1283 case 0x325: return Syriac_DIAC7;
1284 case 0x747:
1285 case 0x303: return Syriac_DIAC8;
1286 case 0x748:
1287 case 0x32D:
1288 case 0x32E:
1289 case 0x330:
1290 case 0x331: return Syriac_DIAC9;
1291 case 0x308: return Syriac_DIAC10;
1292 case 0x304: return Syriac_DIAC11;
1293 case 0x307: return Syriac_DIAC12;
1294 case 0x323: return Syriac_DIAC13;
1295 case 0x743: return Syriac_DIAC14;
1296 case 0x744: return Syriac_DIAC15;
1297 case 0x745: return Syriac_DIAC16;
1298 case 0x746: return Syriac_DIAC17;
1299 default: return Syriac_Norm;
1303 #define ALAPH 0x710
1304 #define DALATH 0x715
1305 #define RISH 0x72A
1307 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1309 CHAR *context_type;
1310 INT *context_shape;
1311 INT dirR, dirL;
1312 int i;
1313 int char_index;
1314 int glyph_index;
1316 if (*pcGlyphs != cChars)
1318 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1319 return;
1322 if (!psa->fLogicalOrder && psa->fRTL)
1324 dirR = 1;
1325 dirL = -1;
1327 else
1329 dirR = -1;
1330 dirL = 1;
1333 load_ot_tables(hdc, psc);
1335 if (!psc->GSUB_Table)
1336 return;
1338 context_type = heap_alloc(cChars);
1339 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1341 for (i = 0; i < cChars; i++)
1342 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1344 for (i = 0; i < cChars; i++)
1346 if (pwcChars[i] == ALAPH)
1348 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1350 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1351 context_shape[i] = Afj;
1352 else if ( rchar != DALATH && rchar != RISH &&
1353 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1354 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1355 context_shape[i] = Afn;
1356 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1357 context_shape[i] = Afx;
1358 else
1359 context_shape[i] = Xn;
1361 else if (context_type[i] == jtR &&
1362 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1363 context_shape[i] = Xr;
1364 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1365 context_shape[i] = Xl;
1366 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)))
1367 context_shape[i] = Xm;
1368 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1369 context_shape[i] = Xr;
1370 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1371 context_shape[i] = Xl;
1372 else
1373 context_shape[i] = Xn;
1376 /* Contextual Shaping */
1377 if (dirL > 0)
1378 char_index = glyph_index = 0;
1379 else
1380 char_index = glyph_index = cChars-1;
1382 while(char_index < cChars && char_index >= 0)
1384 INT nextIndex, offset = 0;
1385 INT prevCount = *pcGlyphs;
1387 /* Apply CCMP first */
1388 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1390 if (prevCount != *pcGlyphs)
1392 offset = *pcGlyphs - prevCount;
1393 if (dirL < 0)
1394 glyph_index -= offset * dirL;
1397 /* Apply the contextual feature */
1398 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1399 if (nextIndex > GSUB_E_NOGLYPH)
1401 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1402 char_index += dirL;
1403 if (!offset)
1404 glyph_index = nextIndex;
1405 else
1407 offset = *pcGlyphs - prevCount;
1408 glyph_index += dirL * (offset + 1);
1411 else
1413 char_index += dirL;
1414 glyph_index += dirL;
1418 heap_free(context_shape);
1419 heap_free(context_type);
1421 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1424 static int combining_lexical_Thaana(WCHAR c)
1426 enum {Thaana_Norm=0, Thaana_FILI};
1428 switch(c)
1430 case 0x7A6:
1431 case 0x7A7:
1432 case 0x7A8:
1433 case 0x7A9:
1434 case 0x7AA:
1435 case 0x7AB:
1436 case 0x7AC:
1437 case 0x7AD:
1438 case 0x7AE:
1439 case 0x7AF: return Thaana_FILI;
1440 default: return Thaana_Norm;
1444 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1446 INT dirL;
1448 if (*pcGlyphs != cChars)
1450 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1451 return;
1454 if (!psa->fLogicalOrder && psa->fRTL)
1455 dirL = -1;
1456 else
1457 dirL = 1;
1459 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1463 * ContextualShape_Phags_pa
1466 #define phags_pa_CANDRABINDU 0xA873
1467 #define phags_pa_START 0xA840
1468 #define phags_pa_END 0xA87F
1470 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1472 INT *context_shape;
1473 INT dirR, dirL;
1474 int i;
1475 int char_index;
1476 int glyph_index;
1478 if (*pcGlyphs != cChars)
1480 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1481 return;
1484 if (!psa->fLogicalOrder && psa->fRTL)
1486 dirR = 1;
1487 dirL = -1;
1489 else
1491 dirR = -1;
1492 dirL = 1;
1495 load_ot_tables(hdc, psc);
1497 if (!psc->GSUB_Table)
1498 return;
1500 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1502 for (i = 0; i < cChars; i++)
1504 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1506 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1507 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1508 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1509 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1511 if (jrchar && jlchar)
1512 context_shape[i] = Xm;
1513 else if (jrchar)
1514 context_shape[i] = Xr;
1515 else if (jlchar)
1516 context_shape[i] = Xl;
1517 else
1518 context_shape[i] = Xn;
1520 else
1521 context_shape[i] = -1;
1524 /* Contextual Shaping */
1525 if (dirL > 0)
1526 char_index = glyph_index = 0;
1527 else
1528 char_index = glyph_index = cChars-1;
1530 while(char_index < cChars && char_index >= 0)
1532 if (context_shape[char_index] >= 0)
1534 INT nextIndex;
1535 INT prevCount = *pcGlyphs;
1536 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1538 if (nextIndex > GSUB_E_NOGLYPH)
1540 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1541 glyph_index = nextIndex;
1542 char_index += dirL;
1544 else
1546 char_index += dirL;
1547 glyph_index += dirL;
1550 else
1552 char_index += dirL;
1553 glyph_index += dirL;
1557 heap_free(context_shape);
1560 static int combining_lexical_Thai(WCHAR c)
1562 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1564 switch(c)
1566 case 0xE31:
1567 case 0xE34:
1568 case 0xE35:
1569 case 0xE36:
1570 case 0xE37: return Thai_ABOVE1;
1571 case 0xE47:
1572 case 0xE4D: return Thai_ABOVE2;
1573 case 0xE48:
1574 case 0xE49:
1575 case 0xE4A:
1576 case 0xE4B: return Thai_ABOVE3;
1577 case 0xE4C:
1578 case 0xE4E: return Thai_ABOVE4;
1579 case 0xE38:
1580 case 0xE39: return Thai_BELOW1;
1581 case 0xE3A: return Thai_BELOW2;
1582 case 0xE33: return Thai_AM;
1583 default: return Thai_Norm;
1587 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1589 INT dirL;
1591 if (*pcGlyphs != cChars)
1593 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1594 return;
1597 if (!psa->fLogicalOrder && psa->fRTL)
1598 dirL = -1;
1599 else
1600 dirL = 1;
1602 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1605 static int combining_lexical_Lao(WCHAR c)
1607 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1609 switch(c)
1611 case 0xEB1:
1612 case 0xEB4:
1613 case 0xEB5:
1614 case 0xEB6:
1615 case 0xEB7:
1616 case 0xEBB:
1617 case 0xECD: return Lao_ABOVE1;
1618 case 0xEC8:
1619 case 0xEC9:
1620 case 0xECA:
1621 case 0xECB:
1622 case 0xECC: return Lao_ABOVE2;
1623 case 0xEBC: return Lao_BELOW1;
1624 case 0xEB8:
1625 case 0xEB9: return Lao_BELOW2;
1626 case 0xEB3: return Lao_AM;
1627 default: return Lao_Norm;
1631 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1633 INT dirL;
1635 if (*pcGlyphs != cChars)
1637 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1638 return;
1641 if (!psa->fLogicalOrder && psa->fRTL)
1642 dirL = -1;
1643 else
1644 dirL = 1;
1646 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1649 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1651 int i;
1653 /* Replace */
1654 pwOutChars[cWalk] = replacements[0];
1655 cWalk=cWalk+1;
1657 /* Insert */
1658 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1660 int j;
1661 for (j = *pcChars; j > cWalk; j--)
1662 pwOutChars[j] = pwOutChars[j-1];
1663 *pcChars= *pcChars+1;
1664 pwOutChars[cWalk] = replacements[i];
1665 cWalk = cWalk+1;
1669 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1671 int i;
1672 int cWalk;
1674 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1676 for (i = 0; vowels[i].base != 0x0; i++)
1678 if (pwOutChars[cWalk] == vowels[i].base)
1680 int o = 0;
1681 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1682 if (vowels[i].parts[1]) { cWalk++; o++; }
1683 if (vowels[i].parts[2]) { cWalk++; o++; }
1684 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1685 break;
1691 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1693 int i;
1694 int offset = 0;
1695 int cWalk;
1697 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1699 for (i = 0; consonants[i].output!= 0x0; i++)
1701 int j;
1702 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1703 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1704 break;
1706 if (consonants[i].parts[j]==0x0) /* matched all */
1708 int k;
1709 j--;
1710 pwOutChars[cWalk] = consonants[i].output;
1711 for(k = cWalk+1; k < *pcChars - j; k++)
1712 pwOutChars[k] = pwOutChars[k+j];
1713 *pcChars = *pcChars - j;
1714 for (k = j ; k > 0; k--)
1715 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1716 offset += j;
1717 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1718 pwLogClust[k]--;
1719 break;
1722 cWalk++;
1726 static void Reorder_Ra_follows_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1728 if (s->ralf >= 0)
1730 int j;
1731 WORD Ra = pwChar[s->start];
1732 WORD H = pwChar[s->start+1];
1734 TRACE("Doing reorder of Ra to %i\n",s->base);
1735 for (j = s->start; j < s->base-1; j++)
1736 pwChar[j] = pwChar[j+2];
1737 pwChar[s->base-1] = Ra;
1738 pwChar[s->base] = H;
1740 s->ralf = s->base-1;
1741 s->base -= 2;
1745 static void Reorder_Ra_follows_matra(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1747 if (s->ralf >= 0)
1749 int j,loc;
1750 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1751 WORD Ra = pwChar[s->start];
1752 WORD H = pwChar[s->start+1];
1753 for (loc = s->end; loc > stop; loc--)
1754 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1755 break;
1757 TRACE("Doing reorder of Ra to %i\n",loc);
1758 for (j = s->start; j < loc-1; j++)
1759 pwChar[j] = pwChar[j+2];
1760 pwChar[loc-1] = Ra;
1761 pwChar[loc] = H;
1763 s->ralf = loc-1;
1764 s->base -= 2;
1765 if (s->blwf >= 0) s->blwf -= 2;
1766 if (s->pref >= 0) s->pref -= 2;
1770 static void Reorder_Ra_follows_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1772 if (s->ralf >= 0)
1774 int j;
1775 WORD Ra = pwChar[s->start];
1776 WORD H = pwChar[s->start+1];
1778 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1779 for (j = s->start; j < s->end-1; j++)
1780 pwChar[j] = pwChar[j+2];
1781 pwChar[s->end-1] = Ra;
1782 pwChar[s->end] = H;
1784 s->ralf = s->end-1;
1785 s->base -= 2;
1786 if (s->blwf >= 0) s->blwf -= 2;
1787 if (s->pref >= 0) s->pref -= 2;
1791 static void Reorder_Matra_precede_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1793 int i;
1795 /* reorder Matras */
1796 if (s->end > s->base)
1798 for (i = 1; i <= s->end-s->base; i++)
1800 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1802 int j;
1803 WCHAR c = pwChar[s->base+i];
1804 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1805 for (j = s->base+i; j > s->base; j--)
1806 pwChar[j] = pwChar[j-1];
1807 pwChar[s->base] = c;
1809 if (s->ralf >= s->base) s->ralf++;
1810 if (s->blwf >= s->base) s->blwf++;
1811 if (s->pref >= s->base) s->pref++;
1812 s->base ++;
1818 static void Reorder_Matra_precede_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1820 int i;
1822 /* reorder Matras */
1823 if (s->end > s->base)
1825 for (i = 1; i <= s->end-s->base; i++)
1827 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1829 int j;
1830 WCHAR c = pwChar[s->base+i];
1831 TRACE("Doing reorder of %x to %i\n",c,s->start);
1832 for (j = s->base+i; j > s->start; j--)
1833 pwChar[j] = pwChar[j-1];
1834 pwChar[s->start] = c;
1836 if (s->ralf >= 0) s->ralf++;
1837 if (s->blwf >= 0) s->blwf++;
1838 if (s->pref >= 0) s->pref++;
1839 s->base ++;
1845 static void SecondReorder_Blwf_follows_matra(const WCHAR *chars, const IndicSyllable *s,
1846 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1848 if (s->blwf >= 0 && g->blwf > g->base)
1850 int j,loc;
1851 int g_offset;
1852 for (loc = s->end; loc > s->blwf; loc--)
1853 if (lexical(chars[loc]) == lex_Matra_below || lexical(chars[loc]) == lex_Matra_above
1854 || lexical(chars[loc]) == lex_Matra_post)
1855 break;
1857 g_offset = (loc - s->blwf) - 1;
1859 if (loc != s->blwf)
1861 WORD blwf = glyphs[g->blwf];
1862 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1863 /* do not care about the pwChar array anymore, just the glyphs */
1864 for (j = 0; j < g_offset; j++)
1865 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1866 glyphs[g->blwf + g_offset] = blwf;
1871 static void SecondReorder_Matra_precede_base(const WCHAR *chars, const IndicSyllable *s,
1872 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1874 int i;
1876 /* reorder previously moved Matras to correct position*/
1877 for (i = s->start; i < s->base; i++)
1879 if (lexical(chars[i]) == lex_Matra_pre)
1881 int j;
1882 int g_start = g->start + i - s->start;
1883 if (g_start < g->base -1 )
1885 WCHAR og = glyphs[g_start];
1886 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1887 for (j = g_start; j < g->base-1; j++)
1888 glyphs[j] = glyphs[j+1];
1889 glyphs[g->base-1] = og;
1895 static void SecondReorder_Pref_precede_base(const IndicSyllable *s,
1896 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1898 if (s->pref >= 0 && g->pref > g->base)
1900 int j;
1901 WCHAR og = glyphs[g->pref];
1902 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1903 for (j = g->pref; j > g->base; j--)
1904 glyphs[j] = glyphs[j-1];
1905 glyphs[g->base] = og;
1909 static void Reorder_Like_Sinhala(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1911 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1912 if (s->start == s->base && s->base == s->end) return;
1913 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1915 Reorder_Ra_follows_base(pwChar, s, lexical);
1916 Reorder_Matra_precede_base(pwChar, s, lexical);
1919 static void Reorder_Like_Devanagari(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1921 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1922 if (s->start == s->base && s->base == s->end) return;
1923 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1925 Reorder_Ra_follows_matra(pwChar, s, lexical);
1926 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1929 static void Reorder_Like_Bengali(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1931 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1932 if (s->start == s->base && s->base == s->end) return;
1933 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1935 Reorder_Ra_follows_base(pwChar, s, lexical);
1936 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1939 static void Reorder_Like_Kannada(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1941 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1942 if (s->start == s->base && s->base == s->end) return;
1943 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1945 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1946 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1949 static void SecondReorder_Like_Telugu(const WCHAR *chars, const IndicSyllable *s,
1950 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1952 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1953 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1954 if (s->start == s->base && s->base == s->end) return;
1955 if (lexical(chars[s->base]) == lex_Vowel) return;
1957 SecondReorder_Blwf_follows_matra(chars, s, glyphs, g, lexical);
1960 static void SecondReorder_Like_Tamil(const WCHAR *chars, const IndicSyllable *s,
1961 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1963 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1964 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1965 if (s->start == s->base && s->base == s->end) return;
1966 if (lexical(chars[s->base]) == lex_Vowel) return;
1968 SecondReorder_Matra_precede_base(chars, s, glyphs, g, lexical);
1969 SecondReorder_Pref_precede_base(s, glyphs, g, lexical);
1973 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1975 if (shift == 0)
1976 return;
1978 if (glyph_index->start > index)
1979 glyph_index->start += shift;
1980 if (glyph_index->base > index)
1981 glyph_index->base+= shift;
1982 if (glyph_index->end > index)
1983 glyph_index->end+= shift;
1984 if (glyph_index->ralf > index)
1985 glyph_index->ralf+= shift;
1986 if (glyph_index->blwf > index)
1987 glyph_index->blwf+= shift;
1988 if (glyph_index->pref > index)
1989 glyph_index->pref+= shift;
1992 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 )
1994 int index = glyph_index->start;
1996 if (!feature)
1997 return;
1999 while(index <= glyph_index->end)
2001 INT nextIndex;
2002 INT prevCount = *pcGlyphs;
2003 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2004 if (nextIndex > GSUB_E_NOGLYPH)
2006 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2007 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2008 index = nextIndex;
2010 else
2011 index++;
2015 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2017 int i = 0;
2018 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)))))
2019 i++;
2020 if (index + i <= end-1)
2021 return index + i;
2022 else
2023 return -1;
2026 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)
2028 INT index, nextIndex;
2029 INT count,g_offset;
2031 count = syllable->base - syllable->start;
2033 g_offset = 0;
2034 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2035 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2037 INT prevCount = *pcGlyphs;
2038 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2039 if (nextIndex > GSUB_E_NOGLYPH)
2041 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2042 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2043 g_offset += (*pcGlyphs - prevCount);
2046 index+=2;
2047 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2051 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)
2053 INT nextIndex;
2054 INT prevCount = *pcGlyphs;
2056 if (syllable->ralf >= 0)
2058 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2059 if (nextIndex > GSUB_E_NOGLYPH)
2061 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2062 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2067 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2069 int i = 0;
2070 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2071 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2072 is_consonant(lexical(pwChars[index+i+1])))))
2073 i++;
2074 if (index + i <= end-1)
2075 return index+i;
2076 else
2077 return -1;
2080 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)
2082 INT index, nextIndex;
2083 INT count, g_offset=0;
2084 INT ralf = syllable->ralf;
2086 count = syllable->end - syllable->base;
2088 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2090 while (index >= 0)
2092 INT prevCount = *pcGlyphs;
2093 if (ralf >=0 && ralf < index)
2095 g_offset--;
2096 ralf = -1;
2099 if (!modern)
2101 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2102 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2103 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2106 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2107 if (nextIndex > GSUB_E_NOGLYPH)
2109 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2110 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2111 g_offset += (*pcGlyphs - prevCount);
2113 else if (!modern)
2115 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2116 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2117 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2120 index+=2;
2121 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2125 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)
2127 int c;
2128 int overall_shift = 0;
2129 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2130 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2131 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2132 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2133 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2134 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2135 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2136 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2137 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2138 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2139 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2140 IndicSyllable glyph_indexs;
2142 for (c = 0; c < syllable_count; c++)
2144 int old_end;
2145 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2146 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2147 old_end = glyph_indexs.end;
2149 if (locl)
2151 TRACE("applying feature locl\n");
2152 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2154 if (nukt)
2156 TRACE("applying feature nukt\n");
2157 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2159 if (akhn)
2161 TRACE("applying feature akhn\n");
2162 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2165 if (rphf)
2166 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2167 if (rkrf)
2169 TRACE("applying feature rkrf\n");
2170 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2172 if (pref)
2173 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2174 if (blwf)
2176 if (!modern)
2177 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2179 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2182 if (half)
2183 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2184 if (pstf)
2186 TRACE("applying feature pstf\n");
2187 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2189 if (vatu)
2191 TRACE("applying feature vatu\n");
2192 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2194 if (cjct)
2196 TRACE("applying feature cjct\n");
2197 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2200 if (second_reorder)
2201 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2203 overall_shift += glyph_indexs.end - old_end;
2207 static inline int unicode_lex(WCHAR c)
2209 int type;
2211 if (!c) return lex_Generic;
2212 if (c == 0x200D) return lex_ZWJ;
2213 if (c == 0x200C) return lex_ZWNJ;
2214 if (c == 0x00A0) return lex_NBSP;
2216 type = get_table_entry( indic_syllabic_table, c );
2218 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2220 switch( type )
2222 case 0x0d07: /* Unknown */
2223 case 0x0e07: /* Unknown */
2224 default: return lex_Generic;
2225 case 0x0001:
2226 case 0x0002:
2227 case 0x0011:
2228 case 0x0012:
2229 case 0x0013:
2230 case 0x0014: return lex_Modifier;
2231 case 0x0003:
2232 case 0x0009:
2233 case 0x000a:
2234 case 0x000b:
2235 case 0x000d:
2236 case 0x000e:
2237 case 0x000f:
2238 case 0x0010: return lex_Consonant;
2239 case 0x0004: return lex_Nukta;
2240 case 0x0005: return lex_Halant;
2241 case 0x0006:
2242 case 0x0008: return lex_Vowel;
2243 case 0x0007:
2244 case 0x0107: return lex_Matra_post;
2245 case 0x0207:
2246 case 0x0307: return lex_Matra_pre;
2247 case 0x0807:
2248 case 0x0907:
2249 case 0x0a07:
2250 case 0x0b07:
2251 case 0x0c07:
2252 case 0x0407: return lex_Composed_Vowel;
2253 case 0x0507: return lex_Matra_above;
2254 case 0x0607: return lex_Matra_below;
2255 case 0x000c:
2256 case 0x0015: return lex_Ra;
2260 static int sinhala_lex(WCHAR c)
2262 switch (c)
2264 case 0x0DDA:
2265 case 0x0DDD:
2266 case 0x0DDC:
2267 case 0x0DDE: return lex_Matra_post;
2268 default:
2269 return unicode_lex(c);
2273 static const VowelComponents Sinhala_vowels[] = {
2274 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2275 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2276 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2277 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2278 {0x0000, {0x0000,0x0000,0x0}}};
2280 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2282 int cCount = cChars;
2283 int i;
2284 WCHAR *input;
2285 IndicSyllable *syllables = NULL;
2286 int syllable_count = 0;
2288 if (*pcGlyphs != cChars)
2290 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2291 return;
2294 input = heap_alloc(3 * cChars * sizeof(*input));
2296 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2298 /* Step 1: Decompose multi part vowels */
2299 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2301 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2303 /* Step 2: Reorder within Syllables */
2304 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2305 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2307 /* Step 3: Strip dangling joiners */
2308 for (i = 0; i < cCount; i++)
2310 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2311 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2312 input[i] = 0x0020;
2315 /* Step 4: Base Form application to syllables */
2316 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2317 *pcGlyphs = cCount;
2318 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2320 heap_free(input);
2321 heap_free(syllables);
2324 static int devanagari_lex(WCHAR c)
2326 switch (c)
2328 case 0x0930: return lex_Ra;
2329 default:
2330 return unicode_lex(c);
2334 static const ConsonantComponents Devanagari_consonants[] ={
2335 {{0x0928, 0x093C, 0x00000}, 0x0929},
2336 {{0x0930, 0x093C, 0x00000}, 0x0931},
2337 {{0x0933, 0x093C, 0x00000}, 0x0934},
2338 {{0x0915, 0x093C, 0x00000}, 0x0958},
2339 {{0x0916, 0x093C, 0x00000}, 0x0959},
2340 {{0x0917, 0x093C, 0x00000}, 0x095A},
2341 {{0x091C, 0x093C, 0x00000}, 0x095B},
2342 {{0x0921, 0x093C, 0x00000}, 0x095C},
2343 {{0x0922, 0x093C, 0x00000}, 0x095D},
2344 {{0x092B, 0x093C, 0x00000}, 0x095E},
2345 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2347 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2349 int cCount = cChars;
2350 WCHAR *input;
2351 IndicSyllable *syllables = NULL;
2352 int syllable_count = 0;
2353 BOOL modern = get_GSUB_Indic2(psa, psc);
2355 if (*pcGlyphs != cChars)
2357 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2358 return;
2361 input = heap_alloc(cChars * sizeof(*input));
2362 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2364 /* Step 1: Compose Consonant and Nukta */
2365 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2366 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2368 /* Step 2: Reorder within Syllables */
2369 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2370 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2371 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2372 *pcGlyphs = cCount;
2374 /* Step 3: Base Form application to syllables */
2375 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2377 heap_free(input);
2378 heap_free(syllables);
2381 static int bengali_lex(WCHAR c)
2383 switch (c)
2385 case 0x09B0: return lex_Ra;
2386 default:
2387 return unicode_lex(c);
2391 static const VowelComponents Bengali_vowels[] = {
2392 {0x09CB, {0x09C7,0x09BE,0x0000}},
2393 {0x09CC, {0x09C7,0x09D7,0x0000}},
2394 {0x0000, {0x0000,0x0000,0x0000}}};
2396 static const ConsonantComponents Bengali_consonants[] = {
2397 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2398 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2399 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2400 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2401 {{0x0000,0x0000,0x0000}, 0x0000}};
2403 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2405 int cCount = cChars;
2406 WCHAR *input;
2407 IndicSyllable *syllables = NULL;
2408 int syllable_count = 0;
2409 BOOL modern = get_GSUB_Indic2(psa, psc);
2411 if (*pcGlyphs != cChars)
2413 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2414 return;
2417 input = heap_alloc(2 * cChars * sizeof(*input));
2418 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2420 /* Step 1: Decompose Vowels and Compose Consonants */
2421 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2422 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2423 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2425 /* Step 2: Reorder within Syllables */
2426 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2427 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2428 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2429 *pcGlyphs = cCount;
2431 /* Step 3: Initial form is only applied to the beginning of words */
2432 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2434 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2436 int index = cCount;
2437 int gCount = 1;
2438 if (index > 0) index++;
2440 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2444 /* Step 4: Base Form application to syllables */
2445 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2447 heap_free(input);
2448 heap_free(syllables);
2451 static int gurmukhi_lex(WCHAR c)
2453 if (c == 0x0A71)
2454 return lex_Modifier;
2455 else
2456 return unicode_lex(c);
2459 static const ConsonantComponents Gurmukhi_consonants[] = {
2460 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2461 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2462 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2463 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2464 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2465 {{0x0000,0x0000,0x0000}, 0x0000}};
2467 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2469 int cCount = cChars;
2470 WCHAR *input;
2471 IndicSyllable *syllables = NULL;
2472 int syllable_count = 0;
2473 BOOL modern = get_GSUB_Indic2(psa, psc);
2475 if (*pcGlyphs != cChars)
2477 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2478 return;
2481 input = heap_alloc(cChars * sizeof(*input));
2482 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2484 /* Step 1: Compose Consonants */
2485 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2486 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2488 /* Step 2: Reorder within Syllables */
2489 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2490 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2491 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2492 *pcGlyphs = cCount;
2494 /* Step 3: Base Form application to syllables */
2495 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2497 heap_free(input);
2498 heap_free(syllables);
2501 static int gujarati_lex(WCHAR c)
2503 switch (c)
2505 case 0x0AB0: return lex_Ra;
2506 default:
2507 return unicode_lex(c);
2511 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2513 int cCount = cChars;
2514 WCHAR *input;
2515 IndicSyllable *syllables = NULL;
2516 int syllable_count = 0;
2517 BOOL modern = get_GSUB_Indic2(psa, psc);
2519 if (*pcGlyphs != cChars)
2521 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2522 return;
2525 input = heap_alloc(cChars * sizeof(*input));
2526 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2528 /* Step 1: Reorder within Syllables */
2529 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2530 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2531 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2532 *pcGlyphs = cCount;
2534 /* Step 2: Base Form application to syllables */
2535 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2537 heap_free(input);
2538 heap_free(syllables);
2541 static int oriya_lex(WCHAR c)
2543 switch (c)
2545 case 0x0B30: return lex_Ra;
2546 default:
2547 return unicode_lex(c);
2551 static const VowelComponents Oriya_vowels[] = {
2552 {0x0B48, {0x0B47,0x0B56,0x0000}},
2553 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2554 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2555 {0x0000, {0x0000,0x0000,0x0000}}};
2557 static const ConsonantComponents Oriya_consonants[] = {
2558 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2559 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2560 {{0x0000,0x0000,0x0000}, 0x0000}};
2562 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2564 int cCount = cChars;
2565 WCHAR *input;
2566 IndicSyllable *syllables = NULL;
2567 int syllable_count = 0;
2568 BOOL modern = get_GSUB_Indic2(psa, psc);
2570 if (*pcGlyphs != cChars)
2572 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2573 return;
2576 input = heap_alloc(2 * cChars * sizeof(*input));
2577 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2579 /* Step 1: Decompose Vowels and Compose Consonants */
2580 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2581 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2582 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2584 /* Step 2: Reorder within Syllables */
2585 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2586 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2587 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2588 *pcGlyphs = cCount;
2590 /* Step 3: Base Form application to syllables */
2591 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2593 heap_free(input);
2594 heap_free(syllables);
2597 static int tamil_lex(WCHAR c)
2599 return unicode_lex(c);
2602 static const VowelComponents Tamil_vowels[] = {
2603 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2604 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2605 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2606 {0x0000, {0x0000,0x0000,0x0000}}};
2608 static const ConsonantComponents Tamil_consonants[] = {
2609 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2610 {{0x0000,0x0000,0x0000}, 0x0000}};
2612 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2614 int cCount = cChars;
2615 WCHAR *input;
2616 IndicSyllable *syllables = NULL;
2617 int syllable_count = 0;
2618 BOOL modern = get_GSUB_Indic2(psa, psc);
2620 if (*pcGlyphs != cChars)
2622 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2623 return;
2626 input = heap_alloc(2 * cChars * sizeof(*input));
2627 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2629 /* Step 1: Decompose Vowels and Compose Consonants */
2630 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2631 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2632 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2634 /* Step 2: Reorder within Syllables */
2635 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2636 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2637 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2638 *pcGlyphs = cCount;
2640 /* Step 3: Base Form application to syllables */
2641 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2643 heap_free(input);
2644 heap_free(syllables);
2647 static int telugu_lex(WCHAR c)
2649 switch (c)
2651 case 0x0C43:
2652 case 0x0C44: return lex_Modifier;
2653 default:
2654 return unicode_lex(c);
2658 static const VowelComponents Telugu_vowels[] = {
2659 {0x0C48, {0x0C46,0x0C56,0x0000}},
2660 {0x0000, {0x0000,0x0000,0x0000}}};
2662 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2664 int cCount = cChars;
2665 WCHAR *input;
2666 IndicSyllable *syllables = NULL;
2667 int syllable_count = 0;
2668 BOOL modern = get_GSUB_Indic2(psa, psc);
2670 if (*pcGlyphs != cChars)
2672 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2673 return;
2676 input = heap_alloc(2 * cChars * sizeof(*input));
2677 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2679 /* Step 1: Decompose Vowels */
2680 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2681 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2683 /* Step 2: Reorder within Syllables */
2684 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2685 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2686 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2687 *pcGlyphs = cCount;
2689 /* Step 3: Base Form application to syllables */
2690 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2692 heap_free(input);
2693 heap_free(syllables);
2696 static int kannada_lex(WCHAR c)
2698 switch (c)
2700 case 0x0CB0: return lex_Ra;
2701 default:
2702 return unicode_lex(c);
2706 static const VowelComponents Kannada_vowels[] = {
2707 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2708 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2709 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2710 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2711 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2712 {0x0000, {0x0000,0x0000,0x0000}}};
2714 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2716 int cCount = cChars;
2717 WCHAR *input;
2718 IndicSyllable *syllables = NULL;
2719 int syllable_count = 0;
2720 BOOL modern = get_GSUB_Indic2(psa, psc);
2722 if (*pcGlyphs != cChars)
2724 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2725 return;
2728 input = heap_alloc(3 * cChars * sizeof(*input));
2729 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2731 /* Step 1: Decompose Vowels */
2732 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2733 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2735 /* Step 2: Reorder within Syllables */
2736 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2737 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2738 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2739 *pcGlyphs = cCount;
2741 /* Step 3: Base Form application to syllables */
2742 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2744 heap_free(input);
2745 heap_free(syllables);
2748 static int malayalam_lex(WCHAR c)
2750 return unicode_lex(c);
2753 static const VowelComponents Malayalam_vowels[] = {
2754 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2755 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2756 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2757 {0x0000, {0x0000,0x0000,0x0000}}};
2759 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2761 int cCount = cChars;
2762 WCHAR *input;
2763 IndicSyllable *syllables = NULL;
2764 int syllable_count = 0;
2765 BOOL modern = get_GSUB_Indic2(psa, psc);
2767 if (*pcGlyphs != cChars)
2769 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2770 return;
2773 input = heap_alloc(2 * cChars * sizeof(*input));
2774 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2776 /* Step 1: Decompose Vowels */
2777 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2778 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2780 /* Step 2: Reorder within Syllables */
2781 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2782 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2783 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2784 *pcGlyphs = cCount;
2786 /* Step 3: Base Form application to syllables */
2787 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2789 heap_free(input);
2790 heap_free(syllables);
2793 static int khmer_lex(WCHAR c)
2795 return unicode_lex(c);
2798 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2800 int cCount = cChars;
2801 WCHAR *input;
2802 IndicSyllable *syllables = NULL;
2803 int syllable_count = 0;
2805 if (*pcGlyphs != cChars)
2807 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2808 return;
2811 input = heap_alloc(cChars * sizeof(*input));
2812 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2814 /* Step 1: Reorder within Syllables */
2815 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2816 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2817 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2818 *pcGlyphs = cCount;
2820 /* Step 2: Base Form application to syllables */
2821 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2823 heap_free(input);
2824 heap_free(syllables);
2827 static inline BOOL mongolian_wordbreak(WCHAR chr)
2829 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2832 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2834 INT *context_shape;
2835 INT dirL;
2836 int i;
2837 int char_index;
2838 int glyph_index;
2840 if (*pcGlyphs != cChars)
2842 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2843 return;
2846 if (!psa->fLogicalOrder && psa->fRTL)
2847 dirL = -1;
2848 else
2849 dirL = 1;
2851 if (!psc->GSUB_Table)
2852 return;
2854 context_shape = heap_alloc(cChars * sizeof(*context_shape));
2856 for (i = 0; i < cChars; i++)
2858 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2860 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2861 context_shape[i] = Xn;
2862 else
2863 context_shape[i] = Xl;
2865 else
2867 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2868 context_shape[i] = Xr;
2869 else
2870 context_shape[i] = Xm;
2874 /* Contextual Shaping */
2875 if (dirL > 0)
2876 char_index = glyph_index = 0;
2877 else
2878 char_index = glyph_index = cChars-1;
2880 while(char_index < cChars && char_index >= 0)
2882 INT nextIndex;
2883 INT prevCount = *pcGlyphs;
2884 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2886 if (nextIndex > GSUB_E_NOGLYPH)
2888 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2889 glyph_index = nextIndex;
2890 char_index += dirL;
2892 else
2894 char_index += dirL;
2895 glyph_index += dirL;
2899 heap_free(context_shape);
2902 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)
2904 int i,k;
2906 for (i = 0; i < cGlyphs; i++)
2908 int char_index[20];
2909 int char_count = 0;
2911 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2912 if (k>=0)
2914 for (; k < cChars && pwLogClust[k] == i; k++)
2915 char_index[char_count++] = k;
2918 if (char_count == 0)
2919 continue;
2921 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2923 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2924 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2926 else
2927 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2930 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2931 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2934 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 )
2936 int i;
2938 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2940 for (i = 0; i < cGlyphs; i++)
2941 if (pGlyphProp[i].sva.fZeroWidth)
2942 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2945 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 )
2947 int i;
2948 for (i = 0; i < cGlyphs; i++)
2950 pGlyphProp[i].sva.fClusterStart = 1;
2951 pGlyphProp[i].sva.fDiacritic = 0;
2952 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2954 if (pwGlyphs[i] == psc->sfp.wgDefault)
2955 pGlyphProp[i].sva.fZeroWidth = 0;
2956 else
2957 pGlyphProp[i].sva.fZeroWidth = 1;
2961 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 )
2963 int i,k;
2964 int initGlyph, finaGlyph;
2965 INT dirR, dirL;
2966 BYTE *spaces;
2968 spaces = heap_alloc(cGlyphs);
2969 memset(spaces,0,cGlyphs);
2971 if (psa->fLogicalOrder && psa->fRTL)
2973 initGlyph = 0;
2974 finaGlyph = cGlyphs-1;
2975 dirR = -1;
2976 dirL = 1;
2978 else
2980 initGlyph = cGlyphs-1;
2981 finaGlyph = 0;
2982 dirR = 1;
2983 dirL = -1;
2986 for (i = 0; i < cGlyphs; i++)
2988 for (k = 0; k < cChars; k++)
2989 if (pwLogClust[k] == i)
2991 if (pwcChars[k] == 0x0020)
2992 spaces[i] = 1;
2996 for (i = 0; i < cGlyphs; i++)
2998 int char_index[20];
2999 int char_count = 0;
3000 BOOL isInit, isFinal;
3002 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3003 if (k>=0)
3005 for (; k < cChars && pwLogClust[k] == i; k++)
3006 char_index[char_count++] = k;
3009 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3010 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3012 if (char_count == 0)
3013 continue;
3015 if (char_count == 1)
3017 if (pwcChars[char_index[0]] == 0x0020) /* space */
3019 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3020 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3022 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3023 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3024 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3026 if (!isInit && !isFinal)
3027 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3028 else if (isInit)
3029 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3030 else
3031 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3033 else if (!isInit)
3035 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3036 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3037 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3038 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3039 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3040 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3041 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3042 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3043 else
3044 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3046 else if (!isInit && !isFinal)
3047 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3048 else
3049 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3051 else if (char_count == 2)
3053 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3054 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3055 else if (!isInit)
3056 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3057 else
3058 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3060 else if (!isInit && !isFinal)
3061 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3062 else
3063 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3066 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3067 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3068 heap_free(spaces);
3071 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 )
3073 int i,k;
3075 for (i = 0; i < cGlyphs; i++)
3077 int char_index[20];
3078 int char_count = 0;
3080 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3081 if (k>=0)
3083 for (; k < cChars && pwLogClust[k] == i; k++)
3084 char_index[char_count++] = k;
3087 if (char_count == 0)
3088 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3089 else
3091 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3092 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3093 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3097 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3098 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3101 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 )
3103 int i;
3104 int finaGlyph;
3105 INT dirL;
3107 if (!psa->fLogicalOrder && psa->fRTL)
3109 finaGlyph = 0;
3110 dirL = -1;
3112 else
3114 finaGlyph = cGlyphs-1;
3115 dirL = 1;
3118 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3120 for (i = 0; i < cGlyphs; i++)
3122 int k;
3123 int char_index[20];
3124 int char_count = 0;
3126 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3127 if (k>=0)
3129 for (; k < cChars && pwLogClust[k] == i; k++)
3130 char_index[char_count++] = k;
3133 if (i == finaGlyph)
3134 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3135 else
3136 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3138 if (char_count == 0)
3139 continue;
3141 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3142 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3144 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3145 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3146 pGlyphProp[i].sva.fClusterStart = 0;
3149 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3151 /* Do not allow justification between marks and their base */
3152 for (i = 0; i < cGlyphs; i++)
3154 if (!pGlyphProp[i].sva.fClusterStart)
3155 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3159 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)
3161 int i,k;
3163 for (i = 0; i < cGlyphs; i++)
3165 int char_index[20];
3166 int char_count = 0;
3168 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3169 if (k>=0)
3171 for (; k < cChars && pwLogClust[k] == i; k++)
3172 char_index[char_count++] = k;
3175 if (char_count == 0)
3176 continue;
3178 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3180 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3181 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3183 else
3184 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3186 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3187 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3190 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)
3192 int i,k;
3194 for (i = 0; i < cGlyphs; i++)
3196 int char_index[20];
3197 int char_count = 0;
3199 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3200 if (k>=0)
3202 for (; k < cChars && pwLogClust[k] == i; k++)
3203 char_index[char_count++] = k;
3206 if (char_count == 0)
3207 continue;
3209 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3211 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3212 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3214 else
3215 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3217 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3218 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3220 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3221 for (i = 0; i < cGlyphs; i++)
3223 if (!pGlyphProp[i].sva.fClusterStart)
3225 pGlyphProp[i].sva.fDiacritic = 0;
3226 pGlyphProp[i].sva.fZeroWidth = 0;
3231 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)
3233 int i,k;
3235 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3236 for (i = 0; i < cGlyphs; i++)
3238 int char_index[20];
3239 int char_count = 0;
3241 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3242 if (k>=0)
3244 for (; k < cChars && pwLogClust[k] == i; k++)
3245 char_index[char_count++] = k;
3248 if (override_gsub)
3250 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3251 pGlyphProp[i].sva.fDiacritic = FALSE;
3252 pGlyphProp[i].sva.fZeroWidth = FALSE;
3255 if (char_count == 0)
3257 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3258 continue;
3261 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3263 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3264 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3266 else
3267 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3269 pGlyphProp[i].sva.fClusterStart = 0;
3270 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3271 switch (lexical(pwcChars[char_index[k]]))
3273 case lex_Matra_pre:
3274 case lex_Matra_post:
3275 case lex_Matra_above:
3276 case lex_Matra_below:
3277 case lex_Modifier:
3278 case lex_Halant:
3279 break;
3280 case lex_ZWJ:
3281 case lex_ZWNJ:
3282 /* check for dangling joiners */
3283 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3284 pGlyphProp[i].sva.fClusterStart = 1;
3285 else
3286 k = char_count;
3287 break;
3288 default:
3289 pGlyphProp[i].sva.fClusterStart = 1;
3290 break;
3294 if (use_syllables)
3296 IndicSyllable *syllables = NULL;
3297 int syllable_count = 0;
3298 BOOL modern = get_GSUB_Indic2(psa, psc);
3300 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3302 for (i = 0; i < syllable_count; i++)
3304 int j;
3305 WORD g = pwLogClust[syllables[i].start];
3306 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3308 if (pwLogClust[j] != g)
3310 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3311 pwLogClust[j] = g;
3316 heap_free(syllables);
3319 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3322 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 )
3324 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3327 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 )
3329 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3332 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 )
3334 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3337 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 )
3339 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3342 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 )
3344 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3347 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 )
3349 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3352 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 )
3354 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3357 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 )
3359 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3362 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 )
3364 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3367 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 )
3369 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3372 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 )
3374 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3377 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)
3379 load_ot_tables(hdc, psc);
3381 if (ShapingData[psa->eScript].charGlyphPropProc)
3382 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3383 else
3384 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3387 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3389 load_ot_tables(hdc, psc);
3391 if (ShapingData[psa->eScript].contextProc)
3392 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3395 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)
3397 int i;
3398 INT dirL;
3400 if (!rpRangeProperties)
3401 return;
3403 load_ot_tables(hdc, psc);
3405 if (!psc->GSUB_Table)
3406 return;
3408 if (scriptInformation[psa->eScript].a.fRTL && (!psa->fLogicalOrder || !psa->fRTL))
3409 dirL = -1;
3410 else
3411 dirL = 1;
3413 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3415 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3416 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3420 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3422 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3423 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3425 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3428 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3430 const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3431 int i;
3433 load_ot_tables(hdc, psc);
3435 if (!psc->GPOS_Table || !psc->otm)
3436 return;
3438 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3440 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3442 LoadedFeature *feature;
3444 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3445 if (!feature)
3446 continue;
3448 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3453 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3455 LoadedFeature *feature;
3456 int i;
3458 if (!ShapingData[psa->eScript].requiredFeatures)
3459 return S_OK;
3461 load_ot_tables(hdc, psc);
3463 /* we need to have at least one of the required features */
3464 i = 0;
3465 while (ShapingData[psa->eScript].requiredFeatures[i])
3467 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3468 if (feature)
3469 return S_OK;
3470 i++;
3473 return USP_E_SCRIPT_NOT_IN_FONT;
3476 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3477 SCRIPT_ANALYSIS *psa, int cMaxTags,
3478 OPENTYPE_TAG *pScriptTags, int *pcTags)
3480 HRESULT hr;
3481 OPENTYPE_TAG searching = 0x00000000;
3483 load_ot_tables(hdc, psc);
3485 if (psa && scriptInformation[psa->eScript].scriptTag)
3486 searching = scriptInformation[psa->eScript].scriptTag;
3488 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3489 if (FAILED(hr))
3490 *pcTags = 0;
3491 return hr;
3494 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3495 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3496 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3497 int *pcTags)
3499 HRESULT hr;
3500 OPENTYPE_TAG searching = 0x00000000;
3501 BOOL fellback = FALSE;
3503 load_ot_tables(hdc, psc);
3505 if (psa && psc->userLang != 0)
3506 searching = psc->userLang;
3508 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3509 if (FAILED(hr))
3511 fellback = TRUE;
3512 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3515 if (FAILED(hr) || fellback)
3516 *pcTags = 0;
3517 if (SUCCEEDED(hr) && fellback && psa)
3518 hr = E_INVALIDARG;
3519 return hr;
3522 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3523 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3524 OPENTYPE_TAG tagLangSys, int cMaxTags,
3525 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3527 HRESULT hr;
3528 BOOL filter = FALSE;
3530 load_ot_tables(hdc, psc);
3532 if (psa && scriptInformation[psa->eScript].scriptTag)
3534 FIXME("Filtering not implemented\n");
3535 filter = TRUE;
3538 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3540 if (FAILED(hr))
3541 *pcTags = 0;
3542 return hr;