usp10: Add ShapeCharGlyphProp_Latin to properly handle zero width character propertie...
[wine.git] / dlls / usp10 / shape.c
bloba4c6d909c72e47cd7e9e749459aa24fb4be6c232
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #define FIRST_ARABIC_CHAR 0x0600
39 #define LAST_ARABIC_CHAR 0x06ff
41 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
42 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
64 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
66 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
67 static void ShapeCharGlyphProp_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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
78 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 );
79 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 );
80 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 );
81 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 );
82 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 );
83 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 );
85 extern const unsigned short indic_syllabic_table[];
86 extern const unsigned short wine_shaping_table[];
87 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
89 enum joining_types {
90 jtU,
91 jtT,
92 jtR,
93 jtL,
94 jtD,
95 jtC
98 enum joined_forms {
99 Xn=0,
103 /* Syriac Alaph */
104 Afj,
105 Afn,
109 typedef struct tagVowelComponents
111 WCHAR base;
112 WCHAR parts[3];
113 } VowelComponents;
115 typedef struct tagConsonantComponents
117 WCHAR parts[3];
118 WCHAR output;
119 } ConsonantComponents;
121 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
123 typedef int (*combining_lexical_function)(WCHAR c);
125 /* the orders of joined_forms and contextual_features need to line up */
126 static const char* contextual_features[] =
128 "isol",
129 "fina",
130 "init",
131 "medi",
132 /* Syriac Alaph */
133 "med2",
134 "fin2",
135 "fin3"
138 static OPENTYPE_FEATURE_RECORD standard_features[] =
140 { MS_MAKE_TAG('c','c','m','p'), 1},
141 { MS_MAKE_TAG('l','o','c','l'), 1},
144 static OPENTYPE_FEATURE_RECORD latin_features[] =
146 { MS_MAKE_TAG('l','o','c','l'), 1},
147 { MS_MAKE_TAG('c','c','m','p'), 1},
148 { MS_MAKE_TAG('l','i','g','a'), 1},
149 { MS_MAKE_TAG('c','l','i','g'), 1},
152 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
154 { MS_MAKE_TAG('k','e','r','n'), 1},
155 { MS_MAKE_TAG('m','a','r','k'), 1},
156 { MS_MAKE_TAG('m','k','m','k'), 1},
159 static OPENTYPE_FEATURE_RECORD arabic_features[] =
161 { MS_MAKE_TAG('r','l','i','g'), 1},
162 { MS_MAKE_TAG('c','a','l','t'), 1},
163 { MS_MAKE_TAG('l','i','g','a'), 1},
164 { MS_MAKE_TAG('d','l','i','g'), 1},
165 { MS_MAKE_TAG('c','s','w','h'), 1},
166 { MS_MAKE_TAG('m','s','e','t'), 1},
169 static const char* required_arabic_features[] =
171 "fina",
172 "init",
173 "medi",
174 "rlig",
175 NULL
178 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
180 { MS_MAKE_TAG('c','u','r','s'), 1},
181 { MS_MAKE_TAG('k','e','r','n'), 1},
182 { MS_MAKE_TAG('m','a','r','k'), 1},
183 { MS_MAKE_TAG('m','k','m','k'), 1},
186 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
188 { MS_MAKE_TAG('c','c','m','p'), 1},
189 { MS_MAKE_TAG('d','l','i','g'), 0},
192 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
194 { MS_MAKE_TAG('k','e','r','n'), 1},
195 { MS_MAKE_TAG('m','a','r','k'), 1},
198 static OPENTYPE_FEATURE_RECORD syriac_features[] =
200 { MS_MAKE_TAG('r','l','i','g'), 1},
201 { MS_MAKE_TAG('c','a','l','t'), 1},
202 { MS_MAKE_TAG('l','i','g','a'), 1},
203 { MS_MAKE_TAG('d','l','i','g'), 1},
206 static const char* required_syriac_features[] =
208 "fina",
209 "fin2",
210 "fin3",
211 "init",
212 "medi",
213 "med2",
214 "rlig",
215 NULL
218 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
220 { MS_MAKE_TAG('k','e','r','n'), 1},
221 { MS_MAKE_TAG('m','a','r','k'), 1},
222 { MS_MAKE_TAG('m','k','m','k'), 1},
225 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
227 /* Presentation forms */
228 { MS_MAKE_TAG('b','l','w','s'), 1},
229 { MS_MAKE_TAG('a','b','v','s'), 1},
230 { MS_MAKE_TAG('p','s','t','s'), 1},
233 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
235 { MS_MAKE_TAG('a','b','v','s'), 1},
236 { MS_MAKE_TAG('b','l','w','s'), 1},
239 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
241 { MS_MAKE_TAG('a','b','v','m'), 1},
242 { MS_MAKE_TAG('b','l','w','m'), 1},
245 static OPENTYPE_FEATURE_RECORD phags_features[] =
247 { MS_MAKE_TAG('a','b','v','s'), 1},
248 { MS_MAKE_TAG('b','l','w','s'), 1},
249 { MS_MAKE_TAG('c','a','l','t'), 1},
252 static OPENTYPE_FEATURE_RECORD thai_features[] =
254 { MS_MAKE_TAG('c','c','m','p'), 1},
257 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
259 { MS_MAKE_TAG('k','e','r','n'), 1},
260 { MS_MAKE_TAG('m','a','r','k'), 1},
261 { MS_MAKE_TAG('m','k','m','k'), 1},
264 static const char* required_lao_features[] =
266 "ccmp",
267 NULL
270 static const char* required_devanagari_features[] =
272 "nukt",
273 "akhn",
274 "rphf",
275 "blwf",
276 "half",
277 "vatu",
278 "pres",
279 "abvs",
280 "blws",
281 "psts",
282 "haln",
283 NULL
286 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
288 { MS_MAKE_TAG('p','r','e','s'), 1},
289 { MS_MAKE_TAG('a','b','v','s'), 1},
290 { MS_MAKE_TAG('b','l','w','s'), 1},
291 { MS_MAKE_TAG('p','s','t','s'), 1},
292 { MS_MAKE_TAG('h','a','l','n'), 1},
293 { MS_MAKE_TAG('c','a','l','t'), 1},
296 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
298 { MS_MAKE_TAG('k','e','r','n'), 1},
299 { MS_MAKE_TAG('d','i','s','t'), 1},
300 { MS_MAKE_TAG('a','b','v','m'), 1},
301 { MS_MAKE_TAG('b','l','w','m'), 1},
304 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
306 { MS_MAKE_TAG('l','i','g','a'), 1},
307 { MS_MAKE_TAG('c','l','i','g'), 1},
310 static const char* required_bengali_features[] =
312 "nukt",
313 "akhn",
314 "rphf",
315 "blwf",
316 "half",
317 "vatu",
318 "pstf",
319 "init",
320 "abvs",
321 "blws",
322 "psts",
323 "haln",
324 NULL
327 static const char* required_gurmukhi_features[] =
329 "nukt",
330 "akhn",
331 "rphf",
332 "blwf",
333 "half",
334 "pstf",
335 "vatu",
336 "cjct",
337 "pres",
338 "abvs",
339 "blws",
340 "psts",
341 "haln",
342 "calt",
343 NULL
346 static const char* required_oriya_features[] =
348 "nukt",
349 "akhn",
350 "rphf",
351 "blwf",
352 "pstf",
353 "cjct",
354 "pres",
355 "abvs",
356 "blws",
357 "psts",
358 "haln",
359 "calt",
360 NULL
363 static const char* required_tamil_features[] =
365 "nukt",
366 "akhn",
367 "rphf",
368 "pref",
369 "half",
370 "pres",
371 "abvs",
372 "blws",
373 "psts",
374 "haln",
375 "calt",
376 NULL
379 static const char* required_telugu_features[] =
381 "nukt",
382 "akhn",
383 "rphf",
384 "pref",
385 "half",
386 "pstf",
387 "cjct",
388 "pres",
389 "abvs",
390 "blws",
391 "psts",
392 "haln",
393 "calt",
394 NULL
397 static OPENTYPE_FEATURE_RECORD khmer_features[] =
399 { MS_MAKE_TAG('p','r','e','s'), 1},
400 { MS_MAKE_TAG('b','l','w','s'), 1},
401 { MS_MAKE_TAG('a','b','v','s'), 1},
402 { MS_MAKE_TAG('p','s','t','s'), 1},
403 { MS_MAKE_TAG('c','l','i','g'), 1},
406 static const char* required_khmer_features[] =
408 "pref",
409 "blwf",
410 "abvf",
411 "pstf",
412 "pres",
413 "blws",
414 "abvs",
415 "psts",
416 "clig",
417 NULL
420 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
422 { MS_MAKE_TAG('d','i','s','t'), 1},
423 { MS_MAKE_TAG('b','l','w','m'), 1},
424 { MS_MAKE_TAG('a','b','v','m'), 1},
425 { MS_MAKE_TAG('m','k','m','k'), 1},
428 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
430 { MS_MAKE_TAG('c','c','m','p'), 1},
431 { MS_MAKE_TAG('l','o','c','l'), 1},
432 { MS_MAKE_TAG('c','a','l','t'), 1},
433 { MS_MAKE_TAG('l','i','g','a'), 1},
436 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
438 { MS_MAKE_TAG('c','c','m','p'), 1},
439 { MS_MAKE_TAG('l','o','c','l'), 1},
440 { MS_MAKE_TAG('c','a','l','t'), 1},
441 { MS_MAKE_TAG('r','l','i','g'), 1},
444 typedef struct ScriptShapeDataTag {
445 TEXTRANGE_PROPERTIES defaultTextRange;
446 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
447 const char** requiredFeatures;
448 OPENTYPE_TAG newOtTag;
449 ContextualShapingProc contextProc;
450 ShapeCharGlyphPropProc charGlyphPropProc;
451 } ScriptShapeData;
453 /* in order of scripts */
454 static const ScriptShapeData ShapingData[] =
456 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
457 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
458 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
459 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
460 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
461 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
462 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
463 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
464 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
465 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
466 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
467 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
468 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
469 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
470 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
471 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
472 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
473 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
474 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
475 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
476 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
477 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
478 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
479 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
480 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
481 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
482 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
483 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
497 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
498 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
499 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
500 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
501 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
502 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
503 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
504 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
505 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
506 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
509 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
510 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
511 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
512 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
513 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
516 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
519 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
520 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
522 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
523 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
524 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
526 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
527 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
528 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
529 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
530 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
531 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
532 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
533 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
534 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
535 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
536 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
537 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
540 extern scriptData scriptInformation[];
542 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
544 int i;
545 int out_index = GSUB_E_NOGLYPH;
547 TRACE("%i lookups\n", feature->lookup_count);
548 for (i = 0; i < feature->lookup_count; i++)
550 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
551 if (out_index != GSUB_E_NOGLYPH)
552 break;
554 if (out_index == GSUB_E_NOGLYPH)
555 TRACE("lookups found no glyphs\n");
556 else
558 int out2;
559 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
560 if (out2!=GSUB_E_NOGLYPH)
561 out_index = out2;
563 return out_index;
566 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
568 UINT charset;
570 if (psc->userScript != 0)
572 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
573 return ShapingData[psa->eScript].newOtTag;
574 else
575 return psc->userScript;
578 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
579 return ShapingData[psa->eScript].newOtTag;
581 if (scriptInformation[psa->eScript].scriptTag)
582 return scriptInformation[psa->eScript].scriptTag;
585 * fall back to the font charset
587 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
588 switch (charset)
590 case ANSI_CHARSET:
591 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
592 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
593 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
594 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
595 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
596 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
597 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
598 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
599 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
600 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
601 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
602 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
603 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
604 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
605 default: return MS_MAKE_TAG('l','a','t','n');
609 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
611 LoadedFeature *feature = NULL;
613 if (psc->GSUB_Table || psc->GPOS_Table)
615 int attempt = 2;
616 OPENTYPE_TAG tags;
617 OPENTYPE_TAG language;
618 OPENTYPE_TAG script = 0x00000000;
619 int cTags;
623 script = get_opentype_script(hdc,psa,psc,(attempt==2));
624 if (psc->userLang != 0)
625 language = psc->userLang;
626 else
627 language = MS_MAKE_TAG('d','f','l','t');
628 attempt--;
630 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
632 } while(attempt && !feature);
634 /* try in the default (latin) table */
635 if (!feature && !script)
636 OpenType_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
639 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
640 return feature;
643 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)
645 LoadedFeature *feature;
647 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
648 if (!feature)
649 return GSUB_E_NOFEATURE;
651 TRACE("applying feature %s\n",feat);
652 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
655 static VOID *load_gsub_table(HDC hdc)
657 VOID* GSUB_Table = NULL;
658 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
659 if (length != GDI_ERROR)
661 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
662 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
663 TRACE("Loaded GSUB table of %i bytes\n",length);
665 return GSUB_Table;
668 static VOID *load_gpos_table(HDC hdc)
670 VOID* GPOS_Table = NULL;
671 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
672 if (length != GDI_ERROR)
674 GPOS_Table = HeapAlloc(GetProcessHeap(),0,length);
675 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
676 TRACE("Loaded GPOS table of %i bytes\n",length);
678 return GPOS_Table;
681 static VOID *load_gdef_table(HDC hdc)
683 VOID* GDEF_Table = NULL;
684 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
685 if (length != GDI_ERROR)
687 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
688 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
689 TRACE("Loaded GDEF table of %i bytes\n",length);
691 return GDEF_Table;
694 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
696 if (!psc->GSUB_Table)
697 psc->GSUB_Table = load_gsub_table(hdc);
698 if (!psc->GPOS_Table)
699 psc->GPOS_Table = load_gpos_table(hdc);
700 if (!psc->GDEF_Table)
701 psc->GDEF_Table = load_gdef_table(hdc);
704 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)
706 WORD *glyphs;
707 INT glyph_count = count;
708 INT rc;
710 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
711 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
712 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
713 if (rc > GSUB_E_NOGLYPH)
714 rc = count - glyph_count;
715 else
716 rc = 0;
718 HeapFree(GetProcessHeap(),0,glyphs);
719 return rc;
722 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
724 int i;
726 for (i = 0; i < cGlyphs; i++)
728 if (!pGlyphProp[i].sva.fClusterStart)
730 int j;
731 for (j = 0; j < cChars; j++)
733 if (pwLogClust[j] == i)
735 int k = j;
736 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
737 k-=1;
738 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
739 pwLogClust[j] = pwLogClust[k];
746 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
748 if (changeCount == 0)
749 return;
750 else
752 int i;
753 int target_glyph = nextIndex - write_dir;
754 int seeking_glyph;
755 int target_index = -1;
756 int replacing_glyph = -1;
757 int changed = 0;
758 int top_logclust = 0;
760 if (changeCount > 0)
762 if (write_dir > 0)
763 target_glyph = nextIndex - changeCount;
764 else
765 target_glyph = nextIndex + (changeCount + 1);
768 seeking_glyph = target_glyph;
769 for (i = 0; i < chars; i++)
770 if (pwLogClust[i] > top_logclust)
771 top_logclust = pwLogClust[i];
773 do {
774 if (write_dir > 0)
775 for (i = 0; i < chars; i++)
777 if (pwLogClust[i] == seeking_glyph)
779 target_index = i;
780 break;
783 else
784 for (i = chars - 1; i >= 0; i--)
786 if (pwLogClust[i] == seeking_glyph)
788 target_index = i;
789 break;
792 if (target_index == -1)
793 seeking_glyph ++;
795 while (target_index == -1 && seeking_glyph <= top_logclust);
797 if (target_index == -1)
799 ERR("Unable to find target glyph\n");
800 return;
803 if (changeCount < 0)
805 /* merge glyphs */
806 for(i = target_index; i < chars && i >= 0; i+=write_dir)
808 if (pwLogClust[i] == target_glyph)
809 continue;
810 if(pwLogClust[i] == replacing_glyph)
811 pwLogClust[i] = target_glyph;
812 else
814 changed--;
815 if (changed >= changeCount)
817 replacing_glyph = pwLogClust[i];
818 pwLogClust[i] = target_glyph;
820 else
821 break;
825 /* renumber trailing indexes*/
826 for(i = target_index; i < chars && i >= 0; i+=write_dir)
828 if (pwLogClust[i] != target_glyph)
829 pwLogClust[i] += changeCount;
832 else
834 for(i = target_index; i < chars && i >= 0; i+=write_dir)
835 pwLogClust[i] += changeCount;
840 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 )
842 if (psc->GSUB_Table)
844 LoadedFeature *feature;
845 int lookup_index;
847 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
848 if (!feature)
849 return GSUB_E_NOFEATURE;
851 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
852 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
854 int i;
856 if (write_dir > 0)
857 i = 0;
858 else
859 i = *pcGlyphs-1;
860 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
861 while(i < *pcGlyphs && i >= 0)
863 INT nextIndex;
864 INT prevCount = *pcGlyphs;
866 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
867 if (*pcGlyphs != prevCount)
869 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
870 i = nextIndex;
872 else
873 i+=write_dir;
876 return *pcGlyphs;
878 return GSUB_E_NOFEATURE;
881 static VOID GPOS_apply_feature(ScriptCache *psc, LPOUTLINETEXTMETRICW lpotm, LPLOGFONTW lplogfont, const SCRIPT_ANALYSIS *analysis, INT* piAdvance, LoadedFeature *feature, const WORD *glyphs, INT glyph_count, GOFFSET *pGoffset)
883 int i;
885 TRACE("%i lookups\n", feature->lookup_count);
886 for (i = 0; i < feature->lookup_count; i++)
888 int j;
889 for (j = 0; j < glyph_count; )
890 j = OpenType_apply_GPOS_lookup(psc, lpotm, lplogfont, analysis, piAdvance, feature->lookups[i], glyphs, j, glyph_count, pGoffset);
894 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
896 OPENTYPE_TAG tag;
897 HRESULT hr;
898 int count = 0;
900 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
902 return(SUCCEEDED(hr));
905 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
907 int i;
908 for (i = *pcGlyphs; i>=index; i--)
909 pwGlyphs[i+1] = pwGlyphs[i];
910 pwGlyphs[index] = glyph;
911 *pcGlyphs = *pcGlyphs+1;
912 if (write_dir < 0)
913 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
914 else
915 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
918 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)
920 CHAR *context_type;
921 int i,g;
922 WCHAR invalid = 0x25cc;
923 WORD invalid_glyph;
925 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
927 /* Mark invalid combinations */
928 for (i = 0; i < cChars; i++)
929 context_type[i] = lex(pwcChars[i]);
931 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
932 for (i = 1, g=1; i < cChars; i++, g++)
934 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
936 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
937 g++;
941 HeapFree(GetProcessHeap(),0,context_type);
944 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
946 if (i + delta < 0)
947 return 0;
948 if ( i+ delta >= cchLen)
949 return 0;
951 i += delta;
953 return chars[i];
956 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
958 if (i + delta < 0)
960 if (psa->fLinkBefore)
961 return jtR;
962 else
963 return jtU;
965 if ( i+ delta >= cchLen)
967 if (psa->fLinkAfter)
968 return jtL;
969 else
970 return jtU;
973 i += delta;
975 if (context_type[i] == jtT)
976 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
977 else
978 return context_type[i];
981 static inline BOOL right_join_causing(CHAR joining_type)
983 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
986 static inline BOOL left_join_causing(CHAR joining_type)
988 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
991 static inline BOOL word_break_causing(WCHAR chr)
993 /* we are working within a string of characters already guareented to
994 be within one script, Syriac, so we do not worry about any character
995 other than the space character outside of that range */
996 return (chr == 0 || chr == 0x20 );
999 static int combining_lexical_Arabic(WCHAR c)
1001 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1003 switch(c)
1005 case 0x064B:
1006 case 0x064C:
1007 case 0x064E:
1008 case 0x064F:
1009 case 0x0652:
1010 case 0x0657:
1011 case 0x0658:
1012 case 0x06E1: return Arab_DIAC1;
1013 case 0x064D:
1014 case 0x0650:
1015 case 0x0656: return Arab_DIAC2;
1016 case 0x0651: return Arab_DIAC3;
1017 case 0x0610:
1018 case 0x0611:
1019 case 0x0612:
1020 case 0x0613:
1021 case 0x0614:
1022 case 0x0659:
1023 case 0x06D6:
1024 case 0x06DC:
1025 case 0x06DF:
1026 case 0x06E0:
1027 case 0x06E2:
1028 case 0x06E4:
1029 case 0x06E7:
1030 case 0x06E8:
1031 case 0x06EB:
1032 case 0x06EC: return Arab_DIAC4;
1033 case 0x06E3:
1034 case 0x06EA:
1035 case 0x06ED: return Arab_DIAC5;
1036 case 0x0670: return Arab_DIAC6;
1037 case 0x0653: return Arab_DIAC7;
1038 case 0x0655:
1039 case 0x0654: return Arab_DIAC8;
1040 default: return Arab_Norm;
1045 * ContextualShape_Arabic
1047 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1049 CHAR *context_type;
1050 INT *context_shape;
1051 INT dirR, dirL;
1052 int i;
1054 if (*pcGlyphs != cChars)
1056 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1057 return;
1060 if (!psa->fLogicalOrder && psa->fRTL)
1062 dirR = 1;
1063 dirL = -1;
1065 else
1067 dirR = -1;
1068 dirL = 1;
1071 load_ot_tables(hdc, psc);
1073 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1074 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1076 for (i = 0; i < cChars; i++)
1077 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1079 for (i = 0; i < cChars; i++)
1081 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1082 context_shape[i] = Xr;
1083 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1084 context_shape[i] = Xl;
1085 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)))
1086 context_shape[i] = Xm;
1087 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1088 context_shape[i] = Xr;
1089 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1090 context_shape[i] = Xl;
1091 else
1092 context_shape[i] = Xn;
1095 /* Contextual Shaping */
1096 i = 0;
1097 while(i < *pcGlyphs)
1099 BOOL shaped = FALSE;
1101 if (psc->GSUB_Table)
1103 INT nextIndex;
1104 INT prevCount = *pcGlyphs;
1105 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1106 if (nextIndex > GSUB_E_NOGLYPH)
1108 i = nextIndex;
1109 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1111 shaped = (nextIndex > GSUB_E_NOGLYPH);
1114 if (!shaped)
1116 if (context_shape[i] == Xn)
1118 WORD newGlyph = pwOutGlyphs[i];
1119 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1121 /* fall back to presentation form B */
1122 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1123 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1124 pwOutGlyphs[i] = newGlyph;
1127 i++;
1131 HeapFree(GetProcessHeap(),0,context_shape);
1132 HeapFree(GetProcessHeap(),0,context_type);
1134 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1137 static int combining_lexical_Hebrew(WCHAR c)
1139 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};
1141 switch(c)
1143 case 0x05B0:
1144 case 0x05B1:
1145 case 0x05B2:
1146 case 0x05B3:
1147 case 0x05B4:
1148 case 0x05B5:
1149 case 0x05B6:
1150 case 0x05BB: return Hebr_DIAC;
1151 case 0x0599:
1152 case 0x05A1:
1153 case 0x05A9:
1154 case 0x05AE: return Hebr_CANT1;
1155 case 0x0597:
1156 case 0x05A8:
1157 case 0x05AC: return Hebr_CANT2;
1158 case 0x0592:
1159 case 0x0593:
1160 case 0x0594:
1161 case 0x0595:
1162 case 0x05A7:
1163 case 0x05AB: return Hebr_CANT3;
1164 case 0x0598:
1165 case 0x059C:
1166 case 0x059E:
1167 case 0x059F: return Hebr_CANT4;
1168 case 0x059D:
1169 case 0x05A0: return Hebr_CANT5;
1170 case 0x059B:
1171 case 0x05A5: return Hebr_CANT6;
1172 case 0x0591:
1173 case 0x05A3:
1174 case 0x05A6: return Hebr_CANT7;
1175 case 0x0596:
1176 case 0x05A4:
1177 case 0x05AA: return Hebr_CANT8;
1178 case 0x059A:
1179 case 0x05AD: return Hebr_CANT9;
1180 case 0x05AF: return Hebr_CANT10;
1181 case 0x05BC: return Hebr_DAGESH;
1182 case 0x05C4: return Hebr_DOTABV;
1183 case 0x05B9: return Hebr_HOLAM;
1184 case 0x05BD: return Hebr_METEG;
1185 case 0x05B7: return Hebr_PATAH;
1186 case 0x05B8: return Hebr_QAMATS;
1187 case 0x05BF: return Hebr_RAFE;
1188 case 0x05C1:
1189 case 0x05C2: return Hebr_SHINSIN;
1190 default: return Hebr_Norm;
1194 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1196 INT dirL;
1198 if (*pcGlyphs != cChars)
1200 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1201 return;
1204 if (!psa->fLogicalOrder && psa->fRTL)
1205 dirL = -1;
1206 else
1207 dirL = 1;
1209 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1213 * ContextualShape_Syriac
1216 static int combining_lexical_Syriac(WCHAR c)
1218 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};
1220 switch(c)
1222 case 0x730:
1223 case 0x733:
1224 case 0x736:
1225 case 0x73A:
1226 case 0x73D: return Syriac_DIAC1;
1227 case 0x731:
1228 case 0x734:
1229 case 0x737:
1230 case 0x73B:
1231 case 0x73E: return Syriac_DIAC2;
1232 case 0x740:
1233 case 0x749:
1234 case 0x74A: return Syriac_DIAC3;
1235 case 0x732:
1236 case 0x735:
1237 case 0x73F: return Syriac_DIAC4;
1238 case 0x738:
1239 case 0x739:
1240 case 0x73C: return Syriac_DIAC5;
1241 case 0x741:
1242 case 0x30A: return Syriac_DIAC6;
1243 case 0x742:
1244 case 0x325: return Syriac_DIAC7;
1245 case 0x747:
1246 case 0x303: return Syriac_DIAC8;
1247 case 0x748:
1248 case 0x32D:
1249 case 0x32E:
1250 case 0x330:
1251 case 0x331: return Syriac_DIAC9;
1252 case 0x308: return Syriac_DIAC10;
1253 case 0x304: return Syriac_DIAC11;
1254 case 0x307: return Syriac_DIAC12;
1255 case 0x323: return Syriac_DIAC13;
1256 case 0x743: return Syriac_DIAC14;
1257 case 0x744: return Syriac_DIAC15;
1258 case 0x745: return Syriac_DIAC16;
1259 case 0x746: return Syriac_DIAC17;
1260 default: return Syriac_Norm;
1264 #define ALAPH 0x710
1265 #define DALATH 0x715
1266 #define RISH 0x72A
1268 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1270 CHAR *context_type;
1271 INT *context_shape;
1272 INT dirR, dirL;
1273 int i;
1275 if (*pcGlyphs != cChars)
1277 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1278 return;
1281 if (!psa->fLogicalOrder && psa->fRTL)
1283 dirR = 1;
1284 dirL = -1;
1286 else
1288 dirR = -1;
1289 dirL = 1;
1292 load_ot_tables(hdc, psc);
1294 if (!psc->GSUB_Table)
1295 return;
1297 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1298 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1300 for (i = 0; i < cChars; i++)
1301 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1303 for (i = 0; i < cChars; i++)
1305 if (pwcChars[i] == ALAPH)
1307 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1309 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1310 context_shape[i] = Afj;
1311 else if ( rchar != DALATH && rchar != RISH &&
1312 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1313 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1314 context_shape[i] = Afn;
1315 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1316 context_shape[i] = Afx;
1317 else
1318 context_shape[i] = Xn;
1320 else if (context_type[i] == jtR &&
1321 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1322 context_shape[i] = Xr;
1323 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1324 context_shape[i] = Xl;
1325 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)))
1326 context_shape[i] = Xm;
1327 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1328 context_shape[i] = Xr;
1329 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1330 context_shape[i] = Xl;
1331 else
1332 context_shape[i] = Xn;
1335 /* Contextual Shaping */
1336 i = 0;
1337 while(i < *pcGlyphs)
1339 INT nextIndex;
1340 INT prevCount = *pcGlyphs;
1341 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1342 if (nextIndex > GSUB_E_NOGLYPH)
1344 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1345 i = nextIndex;
1347 else
1348 i++;
1351 HeapFree(GetProcessHeap(),0,context_shape);
1352 HeapFree(GetProcessHeap(),0,context_type);
1354 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1357 static int combining_lexical_Thaana(WCHAR c)
1359 enum {Thaana_Norm=0, Thaana_FILI};
1361 switch(c)
1363 case 0x7A6:
1364 case 0x7A7:
1365 case 0x7A8:
1366 case 0x7A9:
1367 case 0x7AA:
1368 case 0x7AB:
1369 case 0x7AC:
1370 case 0x7AD:
1371 case 0x7AE:
1372 case 0x7AF: return Thaana_FILI;
1373 default: return Thaana_Norm;
1377 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1379 INT dirL;
1381 if (*pcGlyphs != cChars)
1383 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1384 return;
1387 if (!psa->fLogicalOrder && psa->fRTL)
1388 dirL = -1;
1389 else
1390 dirL = 1;
1392 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1396 * ContextualShape_Phags_pa
1399 #define phags_pa_CANDRABINDU 0xA873
1400 #define phags_pa_START 0xA840
1401 #define phags_pa_END 0xA87F
1403 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1405 INT *context_shape;
1406 INT dirR, dirL;
1407 int i;
1409 if (*pcGlyphs != cChars)
1411 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1412 return;
1415 if (!psa->fLogicalOrder && psa->fRTL)
1417 dirR = 1;
1418 dirL = -1;
1420 else
1422 dirR = -1;
1423 dirL = 1;
1426 load_ot_tables(hdc, psc);
1428 if (!psc->GSUB_Table)
1429 return;
1431 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1433 for (i = 0; i < cChars; i++)
1435 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1437 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1438 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1439 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1440 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1442 if (jrchar && jlchar)
1443 context_shape[i] = Xm;
1444 else if (jrchar)
1445 context_shape[i] = Xr;
1446 else if (jlchar)
1447 context_shape[i] = Xl;
1448 else
1449 context_shape[i] = Xn;
1451 else
1452 context_shape[i] = -1;
1455 /* Contextual Shaping */
1456 i = 0;
1457 while(i < *pcGlyphs)
1459 if (context_shape[i] >= 0)
1461 INT nextIndex;
1462 INT prevCount = *pcGlyphs;
1463 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1464 if (nextIndex > GSUB_E_NOGLYPH)
1466 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1467 i = nextIndex;
1469 else
1470 i++;
1472 else
1473 i++;
1476 HeapFree(GetProcessHeap(),0,context_shape);
1479 static int combining_lexical_Thai(WCHAR c)
1481 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1483 switch(c)
1485 case 0xE31:
1486 case 0xE34:
1487 case 0xE35:
1488 case 0xE36:
1489 case 0xE37: return Thai_ABOVE1;
1490 case 0xE47:
1491 case 0xE4D: return Thai_ABOVE2;
1492 case 0xE48:
1493 case 0xE49:
1494 case 0xE4A:
1495 case 0xE4B: return Thai_ABOVE3;
1496 case 0xE4C:
1497 case 0xE4E: return Thai_ABOVE4;
1498 case 0xE38:
1499 case 0xE39: return Thai_BELOW1;
1500 case 0xE3A: return Thai_BELOW2;
1501 case 0xE33: return Thai_AM;
1502 default: return Thai_Norm;
1506 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1508 INT dirL;
1510 if (*pcGlyphs != cChars)
1512 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1513 return;
1516 if (!psa->fLogicalOrder && psa->fRTL)
1517 dirL = -1;
1518 else
1519 dirL = 1;
1521 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1524 static int combining_lexical_Lao(WCHAR c)
1526 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1528 switch(c)
1530 case 0xEB1:
1531 case 0xEB4:
1532 case 0xEB5:
1533 case 0xEB6:
1534 case 0xEB7:
1535 case 0xEBB:
1536 case 0xECD: return Lao_ABOVE1;
1537 case 0xEC8:
1538 case 0xEC9:
1539 case 0xECA:
1540 case 0xECB:
1541 case 0xECC: return Lao_ABOVE2;
1542 case 0xEBC: return Lao_BELOW1;
1543 case 0xEB8:
1544 case 0xEB9: return Lao_BELOW2;
1545 case 0xEB3: return Lao_AM;
1546 default: return Lao_Norm;
1550 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1552 INT dirL;
1554 if (*pcGlyphs != cChars)
1556 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1557 return;
1560 if (!psa->fLogicalOrder && psa->fRTL)
1561 dirL = -1;
1562 else
1563 dirL = 1;
1565 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1568 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1570 int i;
1572 /* Replace */
1573 pwOutChars[cWalk] = replacements[0];
1574 cWalk=cWalk+1;
1576 /* Insert */
1577 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1579 int j;
1580 for (j = *pcChars; j > cWalk; j--)
1581 pwOutChars[j] = pwOutChars[j-1];
1582 *pcChars= *pcChars+1;
1583 pwOutChars[cWalk] = replacements[i];
1584 cWalk = cWalk+1;
1588 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1590 int i;
1591 int cWalk;
1593 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1595 for (i = 0; vowels[i].base != 0x0; i++)
1597 if (pwOutChars[cWalk] == vowels[i].base)
1599 int o = 0;
1600 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1601 if (vowels[i].parts[1]) { cWalk++; o++; }
1602 if (vowels[i].parts[2]) { cWalk++; o++; }
1603 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1604 break;
1610 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1612 int i;
1613 int offset = 0;
1614 int cWalk;
1616 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1618 for (i = 0; consonants[i].output!= 0x0; i++)
1620 int j;
1621 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1622 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1623 break;
1625 if (consonants[i].parts[j]==0x0) /* matched all */
1627 int k;
1628 j--;
1629 pwOutChars[cWalk] = consonants[i].output;
1630 for(k = cWalk+1; k < *pcChars - j; k++)
1631 pwOutChars[k] = pwOutChars[k+j];
1632 *pcChars = *pcChars - j;
1633 for (k = j ; k > 0; k--)
1634 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1635 offset += j;
1636 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1637 pwLogClust[k]--;
1638 break;
1641 cWalk++;
1645 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1647 if (s->ralf >= 0)
1649 int j;
1650 WORD Ra = pwChar[s->start];
1651 WORD H = pwChar[s->start+1];
1653 TRACE("Doing reorder of Ra to %i\n",s->base);
1654 for (j = s->start; j < s->base-1; j++)
1655 pwChar[j] = pwChar[j+2];
1656 pwChar[s->base-1] = Ra;
1657 pwChar[s->base] = H;
1659 s->ralf = s->base-1;
1660 s->base -= 2;
1664 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1666 if (s->ralf >= 0)
1668 int j,loc;
1669 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1670 WORD Ra = pwChar[s->start];
1671 WORD H = pwChar[s->start+1];
1672 for (loc = s->end; loc > stop; loc--)
1673 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1674 break;
1676 TRACE("Doing reorder of Ra to %i\n",loc);
1677 for (j = s->start; j < loc-1; j++)
1678 pwChar[j] = pwChar[j+2];
1679 pwChar[loc-1] = Ra;
1680 pwChar[loc] = H;
1682 s->ralf = loc-1;
1683 s->base -= 2;
1684 if (s->blwf >= 0) s->blwf -= 2;
1685 if (s->pref >= 0) s->pref -= 2;
1689 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1691 if (s->ralf >= 0)
1693 int j;
1694 WORD Ra = pwChar[s->start];
1695 WORD H = pwChar[s->start+1];
1697 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1698 for (j = s->start; j < s->end-1; j++)
1699 pwChar[j] = pwChar[j+2];
1700 pwChar[s->end-1] = Ra;
1701 pwChar[s->end] = H;
1703 s->ralf = s->end-1;
1704 s->base -= 2;
1705 if (s->blwf >= 0) s->blwf -= 2;
1706 if (s->pref >= 0) s->pref -= 2;
1710 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1712 int i;
1714 /* reorder Matras */
1715 if (s->end > s->base)
1717 for (i = 1; i <= s->end-s->base; i++)
1719 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1721 int j;
1722 WCHAR c = pwChar[s->base+i];
1723 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1724 for (j = s->base+i; j > s->base; j--)
1725 pwChar[j] = pwChar[j-1];
1726 pwChar[s->base] = c;
1728 if (s->ralf >= s->base) s->ralf++;
1729 if (s->blwf >= s->base) s->blwf++;
1730 if (s->pref >= s->base) s->pref++;
1731 s->base ++;
1737 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1739 int i;
1741 /* reorder Matras */
1742 if (s->end > s->base)
1744 for (i = 1; i <= s->end-s->base; i++)
1746 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1748 int j;
1749 WCHAR c = pwChar[s->base+i];
1750 TRACE("Doing reorder of %x to %i\n",c,s->start);
1751 for (j = s->base+i; j > s->start; j--)
1752 pwChar[j] = pwChar[j-1];
1753 pwChar[s->start] = c;
1755 if (s->ralf >= 0) s->ralf++;
1756 if (s->blwf >= 0) s->blwf++;
1757 if (s->pref >= 0) s->pref++;
1758 s->base ++;
1764 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1766 if (s->blwf >= 0 && g->blwf > g->base)
1768 int j,loc;
1769 int g_offset;
1770 for (loc = s->end; loc > s->blwf; loc--)
1771 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1772 break;
1774 g_offset = (loc - s->blwf) - 1;
1776 if (loc != s->blwf)
1778 WORD blwf = glyphs[g->blwf];
1779 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1780 /* do not care about the pwChar array anymore, just the glyphs */
1781 for (j = 0; j < g_offset; j++)
1782 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1783 glyphs[g->blwf + g_offset] = blwf;
1788 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1790 int i;
1792 /* reorder previously moved Matras to correct position*/
1793 for (i = s->start; i < s->base; i++)
1795 if (lexical(pwChar[i]) == lex_Matra_pre)
1797 int j;
1798 int g_start = g->start + i - s->start;
1799 if (g_start < g->base -1 )
1801 WCHAR og = glyphs[g_start];
1802 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1803 for (j = g_start; j < g->base-1; j++)
1804 glyphs[j] = glyphs[j+1];
1805 glyphs[g->base-1] = og;
1811 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1813 if (s->pref >= 0 && g->pref > g->base)
1815 int j;
1816 WCHAR og = glyphs[g->pref];
1817 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1818 for (j = g->pref; j > g->base; j--)
1819 glyphs[j] = glyphs[j-1];
1820 glyphs[g->base] = og;
1824 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1826 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1827 if (s->start == s->base && s->base == s->end) return;
1828 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1830 Reorder_Ra_follows_base(pwChar, s, lexical);
1831 Reorder_Matra_precede_base(pwChar, s, lexical);
1834 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1836 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1837 if (s->start == s->base && s->base == s->end) return;
1838 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1840 Reorder_Ra_follows_matra(pwChar, s, lexical);
1841 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1844 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1846 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1847 if (s->start == s->base && s->base == s->end) return;
1848 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1850 Reorder_Ra_follows_base(pwChar, s, lexical);
1851 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1854 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1856 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1857 if (s->start == s->base && s->base == s->end) return;
1858 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1860 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1861 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1864 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1866 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1867 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1868 if (s->start == s->base && s->base == s->end) return;
1869 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1871 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1874 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1876 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1877 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1878 if (s->start == s->base && s->base == s->end) return;
1879 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1881 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1882 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1886 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1888 if (shift == 0)
1889 return;
1891 if (glyph_index->start > index)
1892 glyph_index->start += shift;
1893 if (glyph_index->base > index)
1894 glyph_index->base+= shift;
1895 if (glyph_index->end > index)
1896 glyph_index->end+= shift;
1897 if (glyph_index->ralf > index)
1898 glyph_index->ralf+= shift;
1899 if (glyph_index->blwf > index)
1900 glyph_index->blwf+= shift;
1901 if (glyph_index->pref > index)
1902 glyph_index->pref+= shift;
1905 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 )
1907 int index = glyph_index->start;
1909 if (!feature)
1910 return;
1912 while(index <= glyph_index->end)
1914 INT nextIndex;
1915 INT prevCount = *pcGlyphs;
1916 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1917 if (nextIndex > GSUB_E_NOGLYPH)
1919 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1920 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1921 index = nextIndex;
1923 else
1924 index++;
1928 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1930 int i = 0;
1931 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)))))
1932 i++;
1933 if (index + i <= end-1)
1934 return index + i;
1935 else
1936 return -1;
1939 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)
1941 INT index, nextIndex;
1942 INT count,g_offset;
1944 count = syllable->base - syllable->start;
1946 g_offset = 0;
1947 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1948 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1950 INT prevCount = *pcGlyphs;
1951 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1952 if (nextIndex > GSUB_E_NOGLYPH)
1954 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1955 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1956 g_offset += (*pcGlyphs - prevCount);
1959 index+=2;
1960 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1964 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)
1966 INT nextIndex;
1967 INT prevCount = *pcGlyphs;
1969 if (syllable->ralf >= 0)
1971 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1972 if (nextIndex > GSUB_E_NOGLYPH)
1974 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1975 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1980 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1982 int i = 0;
1983 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1984 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1985 is_consonant(lexical(pwChars[index+i+1])))))
1986 i++;
1987 if (index + i <= end-1)
1988 return index+i;
1989 else
1990 return -1;
1993 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)
1995 INT index, nextIndex;
1996 INT count, g_offset=0;
1997 INT ralf = syllable->ralf;
1999 count = syllable->end - syllable->base;
2001 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2003 while (index >= 0)
2005 INT prevCount = *pcGlyphs;
2006 if (ralf >=0 && ralf < index)
2008 g_offset--;
2009 ralf = -1;
2012 if (!modern)
2014 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2015 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2016 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2019 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2020 if (nextIndex > GSUB_E_NOGLYPH)
2022 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2023 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2024 g_offset += (*pcGlyphs - prevCount);
2026 else if (!modern)
2028 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2029 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2030 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2033 index+=2;
2034 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2038 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)
2040 int c;
2041 int overall_shift = 0;
2042 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2043 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2044 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2045 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2046 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2047 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2048 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2049 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2050 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2051 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2052 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2053 IndicSyllable glyph_indexs;
2055 for (c = 0; c < syllable_count; c++)
2057 int old_end;
2058 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2059 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2060 old_end = glyph_indexs.end;
2062 if (locl)
2064 TRACE("applying feature locl\n");
2065 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2067 if (nukt)
2069 TRACE("applying feature nukt\n");
2070 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2072 if (akhn)
2074 TRACE("applying feature akhn\n");
2075 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2078 if (rphf)
2079 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2080 if (rkrf)
2082 TRACE("applying feature rkrf\n");
2083 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2085 if (pref)
2086 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2087 if (blwf)
2089 if (!modern)
2090 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2092 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2095 if (half)
2096 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2097 if (pstf)
2099 TRACE("applying feature pstf\n");
2100 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2102 if (vatu)
2104 TRACE("applying feature vatu\n");
2105 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2107 if (cjct)
2109 TRACE("applying feature cjct\n");
2110 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2113 if (second_reorder)
2114 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2116 overall_shift += glyph_indexs.end - old_end;
2120 static inline int unicode_lex(WCHAR c)
2122 int type;
2124 if (!c) return lex_Generic;
2125 if (c == 0x200D) return lex_ZWJ;
2126 if (c == 0x200C) return lex_ZWNJ;
2127 if (c == 0x00A0) return lex_NBSP;
2129 type = get_table_entry( indic_syllabic_table, c );
2131 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2133 switch( type )
2135 case 0x0d07: /* Unknown */
2136 case 0x0e07: /* Unknwon */
2137 default: return lex_Generic;
2138 case 0x0001:
2139 case 0x0002:
2140 case 0x0011:
2141 case 0x0012:
2142 case 0x0013:
2143 case 0x0014: return lex_Modifier;
2144 case 0x0003:
2145 case 0x0009:
2146 case 0x000a:
2147 case 0x000b:
2148 case 0x000d:
2149 case 0x000e:
2150 case 0x000f:
2151 case 0x0010: return lex_Consonant;
2152 case 0x0004: return lex_Nukta;
2153 case 0x0005: return lex_Halant;
2154 case 0x0006:
2155 case 0x0008: return lex_Vowel;
2156 case 0x0007:
2157 case 0x0107: return lex_Matra_post;
2158 case 0x0207:
2159 case 0x0307: return lex_Matra_pre;
2160 case 0x0807:
2161 case 0x0907:
2162 case 0x0a07:
2163 case 0x0b07:
2164 case 0x0c07:
2165 case 0x0407: return lex_Composed_Vowel;
2166 case 0x0507: return lex_Matra_above;
2167 case 0x0607: return lex_Matra_below;
2168 case 0x000c: return lex_Ra;
2172 static int sinhala_lex(WCHAR c)
2174 switch (c)
2176 case 0x0DDA:
2177 case 0x0DDD:
2178 case 0x0DDC:
2179 case 0x0DDE: return lex_Matra_post;
2180 default:
2181 return unicode_lex(c);
2185 static const VowelComponents Sinhala_vowels[] = {
2186 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2187 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2188 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2189 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2190 {0x0000, {0x0000,0x0000,0x0}}};
2192 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2194 int cCount = cChars;
2195 int i;
2196 WCHAR *input;
2197 IndicSyllable *syllables = NULL;
2198 int syllable_count = 0;
2200 if (*pcGlyphs != cChars)
2202 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2203 return;
2206 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2208 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2210 /* Step 1: Decompose multi part vowels */
2211 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2213 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2215 /* Step 2: Reorder within Syllables */
2216 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2217 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2219 /* Step 3: Strip dangling joiners */
2220 for (i = 0; i < cCount; i++)
2222 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2223 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2224 input[i] = 0x0020;
2227 /* Step 4: Base Form application to syllables */
2228 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2229 *pcGlyphs = cCount;
2230 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2232 HeapFree(GetProcessHeap(),0,input);
2233 HeapFree(GetProcessHeap(),0,syllables);
2236 static int devanagari_lex(WCHAR c)
2238 switch (c)
2240 case 0x0930: return lex_Ra;
2241 default:
2242 return unicode_lex(c);
2246 static const ConsonantComponents Devanagari_consonants[] ={
2247 {{0x0928, 0x093C, 0x00000}, 0x0929},
2248 {{0x0930, 0x093C, 0x00000}, 0x0931},
2249 {{0x0933, 0x093C, 0x00000}, 0x0934},
2250 {{0x0915, 0x093C, 0x00000}, 0x0958},
2251 {{0x0916, 0x093C, 0x00000}, 0x0959},
2252 {{0x0917, 0x093C, 0x00000}, 0x095A},
2253 {{0x091C, 0x093C, 0x00000}, 0x095B},
2254 {{0x0921, 0x093C, 0x00000}, 0x095C},
2255 {{0x0922, 0x093C, 0x00000}, 0x095D},
2256 {{0x092B, 0x093C, 0x00000}, 0x095E},
2257 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2259 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2261 int cCount = cChars;
2262 WCHAR *input;
2263 IndicSyllable *syllables = NULL;
2264 int syllable_count = 0;
2265 BOOL modern = get_GSUB_Indic2(psa, psc);
2267 if (*pcGlyphs != cChars)
2269 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2270 return;
2273 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2274 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2276 /* Step 1: Compose Consonant and Nukta */
2277 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2278 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2280 /* Step 2: Reorder within Syllables */
2281 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2282 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2283 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2284 *pcGlyphs = cCount;
2286 /* Step 3: Base Form application to syllables */
2287 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2289 HeapFree(GetProcessHeap(),0,input);
2290 HeapFree(GetProcessHeap(),0,syllables);
2293 static int bengali_lex(WCHAR c)
2295 switch (c)
2297 case 0x09B0: return lex_Ra;
2298 default:
2299 return unicode_lex(c);
2303 static const VowelComponents Bengali_vowels[] = {
2304 {0x09CB, {0x09C7,0x09BE,0x0000}},
2305 {0x09CC, {0x09C7,0x09D7,0x0000}},
2306 {0x0000, {0x0000,0x0000,0x0000}}};
2308 static const ConsonantComponents Bengali_consonants[] = {
2309 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2310 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2311 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2312 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2313 {{0x0000,0x0000,0x0000}, 0x0000}};
2315 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2317 int cCount = cChars;
2318 WCHAR *input;
2319 IndicSyllable *syllables = NULL;
2320 int syllable_count = 0;
2321 BOOL modern = get_GSUB_Indic2(psa, psc);
2323 if (*pcGlyphs != cChars)
2325 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2326 return;
2329 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2330 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2332 /* Step 1: Decompose Vowels and Compose Consonants */
2333 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2334 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2335 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2337 /* Step 2: Reorder within Syllables */
2338 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2339 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2340 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2341 *pcGlyphs = cCount;
2343 /* Step 3: Initial form is only applied to the beginning of words */
2344 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2346 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2348 int index = cCount;
2349 int gCount = 1;
2350 if (index > 0) index++;
2352 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2356 /* Step 4: Base Form application to syllables */
2357 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2359 HeapFree(GetProcessHeap(),0,input);
2360 HeapFree(GetProcessHeap(),0,syllables);
2363 static int gurmukhi_lex(WCHAR c)
2365 if (c == 0x0A71)
2366 return lex_Modifier;
2367 else
2368 return unicode_lex(c);
2371 static const ConsonantComponents Gurmukhi_consonants[] = {
2372 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2373 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2374 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2375 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2376 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2377 {{0x0000,0x0000,0x0000}, 0x0000}};
2379 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2381 int cCount = cChars;
2382 WCHAR *input;
2383 IndicSyllable *syllables = NULL;
2384 int syllable_count = 0;
2385 BOOL modern = get_GSUB_Indic2(psa, psc);
2387 if (*pcGlyphs != cChars)
2389 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2390 return;
2393 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2394 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2396 /* Step 1: Compose Consonants */
2397 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2398 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2400 /* Step 2: Reorder within Syllables */
2401 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2402 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2403 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2404 *pcGlyphs = cCount;
2406 /* Step 3: Base Form application to syllables */
2407 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2409 HeapFree(GetProcessHeap(),0,input);
2410 HeapFree(GetProcessHeap(),0,syllables);
2413 static int gujarati_lex(WCHAR c)
2415 switch (c)
2417 case 0x0AB0: return lex_Ra;
2418 default:
2419 return unicode_lex(c);
2423 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2425 int cCount = cChars;
2426 WCHAR *input;
2427 IndicSyllable *syllables = NULL;
2428 int syllable_count = 0;
2429 BOOL modern = get_GSUB_Indic2(psa, psc);
2431 if (*pcGlyphs != cChars)
2433 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2434 return;
2437 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2438 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2440 /* Step 1: Reorder within Syllables */
2441 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2442 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2443 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2444 *pcGlyphs = cCount;
2446 /* Step 2: Base Form application to syllables */
2447 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2449 HeapFree(GetProcessHeap(),0,input);
2450 HeapFree(GetProcessHeap(),0,syllables);
2453 static int oriya_lex(WCHAR c)
2455 switch (c)
2457 case 0x0B30: return lex_Ra;
2458 default:
2459 return unicode_lex(c);
2463 static const VowelComponents Oriya_vowels[] = {
2464 {0x0B48, {0x0B47,0x0B56,0x0000}},
2465 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2466 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2467 {0x0000, {0x0000,0x0000,0x0000}}};
2469 static const ConsonantComponents Oriya_consonants[] = {
2470 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2471 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2472 {{0x0000,0x0000,0x0000}, 0x0000}};
2474 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2476 int cCount = cChars;
2477 WCHAR *input;
2478 IndicSyllable *syllables = NULL;
2479 int syllable_count = 0;
2480 BOOL modern = get_GSUB_Indic2(psa, psc);
2482 if (*pcGlyphs != cChars)
2484 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2485 return;
2488 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2489 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2491 /* Step 1: Decompose Vowels and Compose Consonants */
2492 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2493 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2494 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2496 /* Step 2: Reorder within Syllables */
2497 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2498 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2499 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2500 *pcGlyphs = cCount;
2502 /* Step 3: Base Form application to syllables */
2503 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2505 HeapFree(GetProcessHeap(),0,input);
2506 HeapFree(GetProcessHeap(),0,syllables);
2509 static int tamil_lex(WCHAR c)
2511 return unicode_lex(c);
2514 static const VowelComponents Tamil_vowels[] = {
2515 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2516 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2517 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2518 {0x0000, {0x0000,0x0000,0x0000}}};
2520 static const ConsonantComponents Tamil_consonants[] = {
2521 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2522 {{0x0000,0x0000,0x0000}, 0x0000}};
2524 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2526 int cCount = cChars;
2527 WCHAR *input;
2528 IndicSyllable *syllables = NULL;
2529 int syllable_count = 0;
2530 BOOL modern = get_GSUB_Indic2(psa, psc);
2532 if (*pcGlyphs != cChars)
2534 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2535 return;
2538 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2539 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2541 /* Step 1: Decompose Vowels and Compose Consonants */
2542 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2543 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2544 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2546 /* Step 2: Reorder within Syllables */
2547 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2548 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2549 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2550 *pcGlyphs = cCount;
2552 /* Step 3: Base Form application to syllables */
2553 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2555 HeapFree(GetProcessHeap(),0,input);
2556 HeapFree(GetProcessHeap(),0,syllables);
2559 static int telugu_lex(WCHAR c)
2561 switch (c)
2563 case 0x0C43:
2564 case 0x0C44: return lex_Modifier;
2565 default:
2566 return unicode_lex(c);
2570 static const VowelComponents Telugu_vowels[] = {
2571 {0x0C48, {0x0C46,0x0C56,0x0000}},
2572 {0x0000, {0x0000,0x0000,0x0000}}};
2574 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2576 int cCount = cChars;
2577 WCHAR *input;
2578 IndicSyllable *syllables = NULL;
2579 int syllable_count = 0;
2580 BOOL modern = get_GSUB_Indic2(psa, psc);
2582 if (*pcGlyphs != cChars)
2584 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2585 return;
2588 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2589 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2591 /* Step 1: Decompose Vowels */
2592 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2593 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2595 /* Step 2: Reorder within Syllables */
2596 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2597 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2598 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2599 *pcGlyphs = cCount;
2601 /* Step 3: Base Form application to syllables */
2602 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2604 HeapFree(GetProcessHeap(),0,input);
2605 HeapFree(GetProcessHeap(),0,syllables);
2608 static int kannada_lex(WCHAR c)
2610 switch (c)
2612 case 0x0CB0: return lex_Ra;
2613 default:
2614 return unicode_lex(c);
2618 static const VowelComponents Kannada_vowels[] = {
2619 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2620 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2621 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2622 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2623 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2624 {0x0000, {0x0000,0x0000,0x0000}}};
2626 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2628 int cCount = cChars;
2629 WCHAR *input;
2630 IndicSyllable *syllables = NULL;
2631 int syllable_count = 0;
2632 BOOL modern = get_GSUB_Indic2(psa, psc);
2634 if (*pcGlyphs != cChars)
2636 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2637 return;
2640 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2641 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2643 /* Step 1: Decompose Vowels */
2644 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2645 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2647 /* Step 2: Reorder within Syllables */
2648 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2649 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2650 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2651 *pcGlyphs = cCount;
2653 /* Step 3: Base Form application to syllables */
2654 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2656 HeapFree(GetProcessHeap(),0,input);
2657 HeapFree(GetProcessHeap(),0,syllables);
2660 static int malayalam_lex(WCHAR c)
2662 return unicode_lex(c);
2665 static const VowelComponents Malayalam_vowels[] = {
2666 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2667 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2668 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2669 {0x0000, {0x0000,0x0000,0x0000}}};
2671 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2673 int cCount = cChars;
2674 WCHAR *input;
2675 IndicSyllable *syllables = NULL;
2676 int syllable_count = 0;
2677 BOOL modern = get_GSUB_Indic2(psa, psc);
2679 if (*pcGlyphs != cChars)
2681 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2682 return;
2685 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2686 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2688 /* Step 1: Decompose Vowels */
2689 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2690 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2692 /* Step 2: Reorder within Syllables */
2693 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2694 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2695 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2696 *pcGlyphs = cCount;
2698 /* Step 3: Base Form application to syllables */
2699 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2701 HeapFree(GetProcessHeap(),0,input);
2702 HeapFree(GetProcessHeap(),0,syllables);
2705 static int khmer_lex(WCHAR c)
2707 return unicode_lex(c);
2710 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2712 int cCount = cChars;
2713 WCHAR *input;
2714 IndicSyllable *syllables = NULL;
2715 int syllable_count = 0;
2717 if (*pcGlyphs != cChars)
2719 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2720 return;
2723 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2724 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2726 /* Step 1: Reorder within Syllables */
2727 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2728 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2729 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2730 *pcGlyphs = cCount;
2732 /* Step 2: Base Form application to syllables */
2733 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2735 HeapFree(GetProcessHeap(),0,input);
2736 HeapFree(GetProcessHeap(),0,syllables);
2739 static inline BOOL mongolian_wordbreak(WCHAR chr)
2741 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2744 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2746 INT *context_shape;
2747 INT dirL;
2748 int i;
2750 if (*pcGlyphs != cChars)
2752 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2753 return;
2756 if (!psa->fLogicalOrder && psa->fRTL)
2757 dirL = -1;
2758 else
2759 dirL = 1;
2761 if (!psc->GSUB_Table)
2762 return;
2764 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2766 for (i = 0; i < cChars; i++)
2768 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2770 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2771 context_shape[i] = Xn;
2772 else
2773 context_shape[i] = Xl;
2775 else
2777 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2778 context_shape[i] = Xr;
2779 else
2780 context_shape[i] = Xm;
2784 /* Contextual Shaping */
2785 i = 0;
2786 while(i < *pcGlyphs)
2788 INT nextIndex;
2789 INT prevCount = *pcGlyphs;
2790 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2791 if (nextIndex > GSUB_E_NOGLYPH)
2793 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2794 i = nextIndex;
2796 else
2797 i++;
2800 HeapFree(GetProcessHeap(),0,context_shape);
2803 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)
2805 int i,k;
2807 for (i = 0; i < cGlyphs; i++)
2809 int char_index[20];
2810 int char_count = 0;
2812 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2813 if (k>=0)
2815 for (; k < cChars && pwLogClust[k] == i; k++)
2816 char_index[char_count++] = k;
2819 if (char_count == 0)
2820 continue;
2822 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2824 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2825 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2827 else
2828 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2831 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2832 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2835 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 )
2837 int i;
2839 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2841 for (i = 0; i < cGlyphs; i++)
2842 if (pGlyphProp[i].sva.fZeroWidth)
2843 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2846 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 )
2848 int i,k;
2849 int initGlyph, finaGlyph;
2850 INT dirR, dirL;
2851 BYTE *spaces;
2853 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2854 memset(spaces,0,cGlyphs);
2856 if (!psa->fLogicalOrder && psa->fRTL)
2858 initGlyph = cGlyphs-1;
2859 finaGlyph = 0;
2860 dirR = 1;
2861 dirL = -1;
2863 else
2865 initGlyph = 0;
2866 finaGlyph = cGlyphs-1;
2867 dirR = -1;
2868 dirL = 1;
2871 for (i = 0; i < cGlyphs; i++)
2873 for (k = 0; k < cChars; k++)
2874 if (pwLogClust[k] == i)
2876 if (pwcChars[k] == 0x0020)
2877 spaces[i] = 1;
2881 for (i = 0; i < cGlyphs; i++)
2883 int char_index[20];
2884 int char_count = 0;
2885 BOOL isInit, isFinal;
2887 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2888 if (k>=0)
2890 for (; k < cChars && pwLogClust[k] == i; k++)
2891 char_index[char_count++] = k;
2894 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2895 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2897 if (char_count == 0)
2898 continue;
2900 if (char_count == 1)
2902 if (pwcChars[char_index[0]] == 0x0020) /* space */
2904 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2905 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2907 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2908 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2909 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2911 if (!isInit && !isFinal)
2912 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2913 else if (isInit)
2914 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2915 else
2916 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2918 else if (!isInit)
2920 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2921 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2922 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2923 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2924 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2925 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2926 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2927 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2928 else
2929 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2931 else if (!isInit && !isFinal)
2932 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2933 else
2934 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2936 else if (char_count == 2)
2938 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2939 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2940 else if (!isInit)
2941 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2942 else
2943 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2945 else if (!isInit && !isFinal)
2946 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2947 else
2948 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2951 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2952 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2953 HeapFree(GetProcessHeap(),0,spaces);
2956 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 )
2958 int i,k;
2960 for (i = 0; i < cGlyphs; i++)
2962 int char_index[20];
2963 int char_count = 0;
2965 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2966 if (k>=0)
2968 for (; k < cChars && pwLogClust[k] == i; k++)
2969 char_index[char_count++] = k;
2972 if (char_count == 0)
2973 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2974 else
2976 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2977 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2978 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2982 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2983 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2986 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 )
2988 int i;
2989 int finaGlyph;
2990 INT dirL;
2992 if (!psa->fLogicalOrder && psa->fRTL)
2994 finaGlyph = 0;
2995 dirL = -1;
2997 else
2999 finaGlyph = cGlyphs-1;
3000 dirL = 1;
3003 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3005 for (i = 0; i < cGlyphs; i++)
3007 int k;
3008 int char_index[20];
3009 int char_count = 0;
3011 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3012 if (k>=0)
3014 for (; k < cChars && pwLogClust[k] == i; k++)
3015 char_index[char_count++] = k;
3018 if (i == finaGlyph)
3019 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3020 else
3021 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3023 if (char_count == 0)
3024 continue;
3026 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3027 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3029 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3030 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3031 pGlyphProp[i].sva.fClusterStart = 0;
3034 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3036 /* Do not allow justification between marks and their base */
3037 for (i = 0; i < cGlyphs; i++)
3039 if (!pGlyphProp[i].sva.fClusterStart)
3040 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3044 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)
3046 int i,k;
3048 for (i = 0; i < cGlyphs; i++)
3050 int char_index[20];
3051 int char_count = 0;
3053 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3054 if (k>=0)
3056 for (; k < cChars && pwLogClust[k] == i; k++)
3057 char_index[char_count++] = k;
3060 if (char_count == 0)
3061 continue;
3063 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3065 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3066 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3068 else
3069 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3071 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3072 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3075 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)
3077 int i,k;
3079 for (i = 0; i < cGlyphs; i++)
3081 int char_index[20];
3082 int char_count = 0;
3084 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3085 if (k>=0)
3087 for (; k < cChars && pwLogClust[k] == i; k++)
3088 char_index[char_count++] = k;
3091 if (char_count == 0)
3092 continue;
3094 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3096 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3097 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3099 else
3100 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3102 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3103 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3105 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3106 for (i = 0; i < cGlyphs; i++)
3108 if (!pGlyphProp[i].sva.fClusterStart)
3110 pGlyphProp[i].sva.fDiacritic = 0;
3111 pGlyphProp[i].sva.fZeroWidth = 0;
3116 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)
3118 int i,k;
3120 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3121 for (i = 0; i < cGlyphs; i++)
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 (override_gsub)
3135 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3136 pGlyphProp[i].sva.fDiacritic = FALSE;
3137 pGlyphProp[i].sva.fZeroWidth = FALSE;
3140 if (char_count == 0)
3142 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3143 continue;
3146 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3148 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3149 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3151 else
3152 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3154 pGlyphProp[i].sva.fClusterStart = 0;
3155 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3156 switch (lexical(pwcChars[char_index[k]]))
3158 case lex_Matra_pre:
3159 case lex_Matra_post:
3160 case lex_Matra_above:
3161 case lex_Matra_below:
3162 case lex_Modifier:
3163 case lex_Halant:
3164 break;
3165 case lex_ZWJ:
3166 case lex_ZWNJ:
3167 /* check for dangling joiners */
3168 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3169 pGlyphProp[i].sva.fClusterStart = 1;
3170 else
3171 k = char_count;
3172 break;
3173 default:
3174 pGlyphProp[i].sva.fClusterStart = 1;
3175 break;
3179 if (use_syllables)
3181 IndicSyllable *syllables = NULL;
3182 int syllable_count = 0;
3183 BOOL modern = get_GSUB_Indic2(psa, psc);
3185 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3187 for (i = 0; i < syllable_count; i++)
3189 int j;
3190 WORD g = pwLogClust[syllables[i].start];
3191 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3193 if (pwLogClust[j] != g)
3195 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3196 pwLogClust[j] = g;
3201 HeapFree(GetProcessHeap(), 0, syllables);
3204 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3207 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 )
3209 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3212 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 )
3214 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3217 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 )
3219 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3222 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 )
3224 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3227 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 )
3229 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3232 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 )
3234 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3237 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 )
3239 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3242 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 )
3244 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3247 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 )
3249 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3252 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 )
3254 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3257 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 )
3259 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3262 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)
3264 load_ot_tables(hdc, psc);
3266 if (ShapingData[psa->eScript].charGlyphPropProc)
3267 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3268 else
3269 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3272 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3274 load_ot_tables(hdc, psc);
3276 if (ShapingData[psa->eScript].contextProc)
3277 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3280 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)
3282 int i;
3283 INT dirL;
3285 if (!rpRangeProperties)
3286 return;
3288 load_ot_tables(hdc, psc);
3290 if (!psc->GSUB_Table)
3291 return;
3293 if (!psa->fLogicalOrder && psa->fRTL)
3294 dirL = -1;
3295 else
3296 dirL = 1;
3298 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3300 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3301 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3305 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3307 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3308 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3310 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3313 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3315 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3316 int i;
3318 rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3320 if (!rpRangeProperties)
3321 return;
3323 load_ot_tables(hdc, psc);
3325 if (!psc->GPOS_Table || !psc->otm)
3326 return;
3328 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3330 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3332 LoadedFeature *feature;
3334 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3335 if (!feature)
3336 continue;
3338 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3343 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3345 LoadedFeature *feature;
3346 int i;
3348 if (!ShapingData[psa->eScript].requiredFeatures)
3349 return S_OK;
3351 load_ot_tables(hdc, psc);
3353 /* we need to have at least one of the required features */
3354 i = 0;
3355 while (ShapingData[psa->eScript].requiredFeatures[i])
3357 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3358 if (feature)
3359 return S_OK;
3360 i++;
3363 return USP_E_SCRIPT_NOT_IN_FONT;
3366 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3367 SCRIPT_ANALYSIS *psa, int cMaxTags,
3368 OPENTYPE_TAG *pScriptTags, int *pcTags)
3370 HRESULT hr;
3371 OPENTYPE_TAG searching = 0x00000000;
3373 load_ot_tables(hdc, psc);
3375 if (psa && scriptInformation[psa->eScript].scriptTag)
3376 searching = scriptInformation[psa->eScript].scriptTag;
3378 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3379 if (FAILED(hr))
3380 *pcTags = 0;
3381 return hr;
3384 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3385 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3386 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3387 int *pcTags)
3389 HRESULT hr;
3390 OPENTYPE_TAG searching = 0x00000000;
3391 BOOL fellback = FALSE;
3393 load_ot_tables(hdc, psc);
3395 if (psa && psc->userLang != 0)
3396 searching = psc->userLang;
3398 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3399 if (FAILED(hr))
3401 fellback = TRUE;
3402 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3405 if (FAILED(hr) || fellback)
3406 *pcTags = 0;
3407 if (SUCCEEDED(hr) && fellback && psa)
3408 hr = E_INVALIDARG;
3409 return hr;
3412 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3413 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3414 OPENTYPE_TAG tagLangSys, int cMaxTags,
3415 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3417 HRESULT hr;
3418 BOOL filter = FALSE;
3420 load_ot_tables(hdc, psc);
3422 if (psa && scriptInformation[psa->eScript].scriptTag)
3424 FIXME("Filtering not implemented\n");
3425 filter = TRUE;
3428 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3430 if (FAILED(hr))
3431 *pcTags = 0;
3432 return hr;