usp10: GPOS Mark to Base seeks back in the string to the first glyph that is not...
[wine.git] / dlls / usp10 / shape.c
blobac18b13fa9bda3c81cc1bf308d41df82acfde726
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_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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
78 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 );
79 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 );
80 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 );
81 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 );
82 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 );
84 extern const unsigned short indic_syllabic_table[];
85 extern const unsigned short wine_shaping_table[];
86 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
88 enum joining_types {
89 jtU,
90 jtT,
91 jtR,
92 jtL,
93 jtD,
94 jtC
97 enum joined_forms {
98 Xn=0,
99 Xr,
102 /* Syriac Alaph */
103 Afj,
104 Afn,
108 typedef struct tagVowelComponents
110 WCHAR base;
111 WCHAR parts[3];
112 } VowelComponents;
114 typedef struct tagConsonantComponents
116 WCHAR parts[3];
117 WCHAR output;
118 } ConsonantComponents;
120 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
122 typedef int (*combining_lexical_function)(WCHAR c);
124 /* the orders of joined_forms and contextual_features need to line up */
125 static const char* contextual_features[] =
127 "isol",
128 "fina",
129 "init",
130 "medi",
131 /* Syriac Alaph */
132 "med2",
133 "fin2",
134 "fin3"
137 static OPENTYPE_FEATURE_RECORD standard_features[] =
139 { MS_MAKE_TAG('c','c','m','p'), 1},
140 { MS_MAKE_TAG('l','o','c','l'), 1},
143 static OPENTYPE_FEATURE_RECORD latin_features[] =
145 { MS_MAKE_TAG('l','i','g','a'), 1},
146 { MS_MAKE_TAG('c','l','i','g'), 1},
149 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
151 { MS_MAKE_TAG('k','e','r','n'), 1},
152 { MS_MAKE_TAG('m','a','r','k'), 1},
153 { MS_MAKE_TAG('m','k','m','k'), 1},
156 static OPENTYPE_FEATURE_RECORD arabic_features[] =
158 { MS_MAKE_TAG('r','l','i','g'), 1},
159 { MS_MAKE_TAG('c','a','l','t'), 1},
160 { MS_MAKE_TAG('l','i','g','a'), 1},
161 { MS_MAKE_TAG('d','l','i','g'), 1},
162 { MS_MAKE_TAG('c','s','w','h'), 1},
163 { MS_MAKE_TAG('m','s','e','t'), 1},
166 static const char* required_arabic_features[] =
168 "fina",
169 "init",
170 "medi",
171 "rlig",
172 NULL
175 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
177 { MS_MAKE_TAG('c','u','r','s'), 1},
178 { MS_MAKE_TAG('k','e','r','n'), 1},
179 { MS_MAKE_TAG('m','a','r','k'), 1},
180 { MS_MAKE_TAG('m','k','m','k'), 1},
183 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
185 { MS_MAKE_TAG('c','c','m','p'), 1},
186 { MS_MAKE_TAG('d','l','i','g'), 0},
189 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
191 { MS_MAKE_TAG('k','e','r','n'), 1},
192 { MS_MAKE_TAG('m','a','r','k'), 1},
195 static OPENTYPE_FEATURE_RECORD syriac_features[] =
197 { MS_MAKE_TAG('r','l','i','g'), 1},
198 { MS_MAKE_TAG('c','a','l','t'), 1},
199 { MS_MAKE_TAG('l','i','g','a'), 1},
200 { MS_MAKE_TAG('d','l','i','g'), 1},
203 static const char* required_syriac_features[] =
205 "fina",
206 "fin2",
207 "fin3",
208 "init",
209 "medi",
210 "med2",
211 "rlig",
212 NULL
215 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
217 { MS_MAKE_TAG('k','e','r','n'), 1},
218 { MS_MAKE_TAG('m','a','r','k'), 1},
219 { MS_MAKE_TAG('m','k','m','k'), 1},
222 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
224 /* Presentation forms */
225 { MS_MAKE_TAG('b','l','w','s'), 1},
226 { MS_MAKE_TAG('a','b','v','s'), 1},
227 { MS_MAKE_TAG('p','s','t','s'), 1},
230 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
232 { MS_MAKE_TAG('a','b','v','s'), 1},
233 { MS_MAKE_TAG('b','l','w','s'), 1},
236 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
238 { MS_MAKE_TAG('a','b','v','m'), 1},
239 { MS_MAKE_TAG('b','l','w','m'), 1},
242 static OPENTYPE_FEATURE_RECORD phags_features[] =
244 { MS_MAKE_TAG('a','b','v','s'), 1},
245 { MS_MAKE_TAG('b','l','w','s'), 1},
246 { MS_MAKE_TAG('c','a','l','t'), 1},
249 static OPENTYPE_FEATURE_RECORD thai_features[] =
251 { MS_MAKE_TAG('c','c','m','p'), 1},
254 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
256 { MS_MAKE_TAG('k','e','r','n'), 1},
257 { MS_MAKE_TAG('m','a','r','k'), 1},
258 { MS_MAKE_TAG('m','k','m','k'), 1},
261 static const char* required_lao_features[] =
263 "ccmp",
264 NULL
267 static const char* required_devanagari_features[] =
269 "nukt",
270 "akhn",
271 "rphf",
272 "blwf",
273 "half",
274 "vatu",
275 "pres",
276 "abvs",
277 "blws",
278 "psts",
279 "haln",
280 NULL
283 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
285 { MS_MAKE_TAG('p','r','e','s'), 1},
286 { MS_MAKE_TAG('a','b','v','s'), 1},
287 { MS_MAKE_TAG('b','l','w','s'), 1},
288 { MS_MAKE_TAG('p','s','t','s'), 1},
289 { MS_MAKE_TAG('h','a','l','n'), 1},
290 { MS_MAKE_TAG('c','a','l','t'), 1},
293 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
295 { MS_MAKE_TAG('k','e','r','n'), 1},
296 { MS_MAKE_TAG('d','i','s','t'), 1},
297 { MS_MAKE_TAG('a','b','v','m'), 1},
298 { MS_MAKE_TAG('b','l','w','m'), 1},
301 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
303 { MS_MAKE_TAG('l','i','g','a'), 1},
304 { MS_MAKE_TAG('c','l','i','g'), 1},
307 static const char* required_bengali_features[] =
309 "nukt",
310 "akhn",
311 "rphf",
312 "blwf",
313 "half",
314 "vatu",
315 "pstf",
316 "init",
317 "abvs",
318 "blws",
319 "psts",
320 "haln",
321 NULL
324 static const char* required_gurmukhi_features[] =
326 "nukt",
327 "akhn",
328 "rphf",
329 "blwf",
330 "half",
331 "pstf",
332 "vatu",
333 "cjct",
334 "pres",
335 "abvs",
336 "blws",
337 "psts",
338 "haln",
339 "calt",
340 NULL
343 static const char* required_oriya_features[] =
345 "nukt",
346 "akhn",
347 "rphf",
348 "blwf",
349 "pstf",
350 "cjct",
351 "pres",
352 "abvs",
353 "blws",
354 "psts",
355 "haln",
356 "calt",
357 NULL
360 static const char* required_tamil_features[] =
362 "nukt",
363 "akhn",
364 "rphf",
365 "pref",
366 "half",
367 "pres",
368 "abvs",
369 "blws",
370 "psts",
371 "haln",
372 "calt",
373 NULL
376 static const char* required_telugu_features[] =
378 "nukt",
379 "akhn",
380 "rphf",
381 "pref",
382 "half",
383 "pstf",
384 "cjct",
385 "pres",
386 "abvs",
387 "blws",
388 "psts",
389 "haln",
390 "calt",
391 NULL
394 static OPENTYPE_FEATURE_RECORD khmer_features[] =
396 { MS_MAKE_TAG('p','r','e','s'), 1},
397 { MS_MAKE_TAG('b','l','w','s'), 1},
398 { MS_MAKE_TAG('a','b','v','s'), 1},
399 { MS_MAKE_TAG('p','s','t','s'), 1},
400 { MS_MAKE_TAG('c','l','i','g'), 1},
403 static const char* required_khmer_features[] =
405 "pref",
406 "blwf",
407 "abvf",
408 "pstf",
409 "pres",
410 "blws",
411 "abvs",
412 "psts",
413 "clig",
414 NULL
417 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
419 { MS_MAKE_TAG('d','i','s','t'), 1},
420 { MS_MAKE_TAG('b','l','w','m'), 1},
421 { MS_MAKE_TAG('a','b','v','m'), 1},
422 { MS_MAKE_TAG('m','k','m','k'), 1},
425 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
427 { MS_MAKE_TAG('c','c','m','p'), 1},
428 { MS_MAKE_TAG('l','o','c','l'), 1},
429 { MS_MAKE_TAG('c','a','l','t'), 1},
430 { MS_MAKE_TAG('l','i','g','a'), 1},
433 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
435 { MS_MAKE_TAG('c','c','m','p'), 1},
436 { MS_MAKE_TAG('l','o','c','l'), 1},
437 { MS_MAKE_TAG('c','a','l','t'), 1},
438 { MS_MAKE_TAG('r','l','i','g'), 1},
441 typedef struct ScriptShapeDataTag {
442 TEXTRANGE_PROPERTIES defaultTextRange;
443 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
444 const char** requiredFeatures;
445 OPENTYPE_TAG newOtTag;
446 ContextualShapingProc contextProc;
447 ShapeCharGlyphPropProc charGlyphPropProc;
448 } ScriptShapeData;
450 /* in order of scripts */
451 static const ScriptShapeData ShapingData[] =
453 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
454 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
455 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
456 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
457 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
458 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
459 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
460 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
461 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
462 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
463 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
464 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
465 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
466 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
467 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
468 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
469 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
470 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
471 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
472 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
473 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
474 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
475 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
476 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
477 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
478 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
479 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
480 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
481 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
482 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
483 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
497 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
498 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
499 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
500 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
501 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
502 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
503 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
504 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
505 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
506 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
507 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
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 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
516 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
522 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
523 {{ 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 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
533 {{ latin_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
534 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
537 extern scriptData scriptInformation[];
539 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
541 int i;
542 int out_index = GSUB_E_NOGLYPH;
544 TRACE("%i lookups\n", feature->lookup_count);
545 for (i = 0; i < feature->lookup_count; i++)
547 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
548 if (out_index != GSUB_E_NOGLYPH)
549 break;
551 if (out_index == GSUB_E_NOGLYPH)
552 TRACE("lookups found no glyphs\n");
553 else
555 int out2;
556 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
557 if (out2!=GSUB_E_NOGLYPH)
558 out_index = out2;
560 return out_index;
563 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
565 UINT charset;
567 if (psc->userScript != 0)
569 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
570 return ShapingData[psa->eScript].newOtTag;
571 else
572 return psc->userScript;
575 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
576 return ShapingData[psa->eScript].newOtTag;
578 if (scriptInformation[psa->eScript].scriptTag)
579 return scriptInformation[psa->eScript].scriptTag;
582 * fall back to the font charset
584 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
585 switch (charset)
587 case ANSI_CHARSET:
588 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
589 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
590 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
591 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
592 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
593 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
594 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
595 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
596 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
597 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
598 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
599 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
600 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
601 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
602 default: return MS_MAKE_TAG('l','a','t','n');
606 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
608 LoadedFeature *feature = NULL;
610 if (psc->GSUB_Table || psc->GPOS_Table)
612 int attempt = 2;
613 OPENTYPE_TAG tags;
614 OPENTYPE_TAG language;
615 OPENTYPE_TAG script;
616 int cTags;
620 script = get_opentype_script(hdc,psa,psc,(attempt==2));
621 if (psc->userLang != 0)
622 language = psc->userLang;
623 else
624 language = MS_MAKE_TAG('d','f','l','t');
625 attempt--;
627 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
629 } while(attempt && !feature);
631 /* try in the default (latin) table */
632 if (!feature)
633 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);
636 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
637 return feature;
640 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)
642 LoadedFeature *feature;
644 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
645 if (!feature)
646 return GSUB_E_NOFEATURE;
648 TRACE("applying feature %s\n",feat);
649 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
652 static VOID *load_gsub_table(HDC hdc)
654 VOID* GSUB_Table = NULL;
655 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
656 if (length != GDI_ERROR)
658 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
659 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
660 TRACE("Loaded GSUB table of %i bytes\n",length);
662 return GSUB_Table;
665 static VOID *load_gpos_table(HDC hdc)
667 VOID* GPOS_Table = NULL;
668 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
669 if (length != GDI_ERROR)
671 GPOS_Table = HeapAlloc(GetProcessHeap(),0,length);
672 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
673 TRACE("Loaded GPOS table of %i bytes\n",length);
675 return GPOS_Table;
678 static VOID *load_gdef_table(HDC hdc)
680 VOID* GDEF_Table = NULL;
681 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
682 if (length != GDI_ERROR)
684 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
685 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
686 TRACE("Loaded GDEF table of %i bytes\n",length);
688 return GDEF_Table;
691 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
693 if (!psc->GSUB_Table)
694 psc->GSUB_Table = load_gsub_table(hdc);
695 if (!psc->GPOS_Table)
696 psc->GPOS_Table = load_gpos_table(hdc);
697 if (!psc->GDEF_Table)
698 psc->GDEF_Table = load_gdef_table(hdc);
701 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)
703 WORD *glyphs;
704 INT glyph_count = count;
705 INT rc;
707 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
708 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
709 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
710 if (rc > GSUB_E_NOGLYPH)
711 rc = count - glyph_count;
712 else
713 rc = 0;
715 HeapFree(GetProcessHeap(),0,glyphs);
716 return rc;
719 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
721 int i;
723 for (i = 0; i < cGlyphs; i++)
725 if (!pGlyphProp[i].sva.fClusterStart)
727 int j;
728 for (j = 0; j < cChars; j++)
730 if (pwLogClust[j] == i)
732 int k = j;
733 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
734 k-=1;
735 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
736 pwLogClust[j] = pwLogClust[k];
743 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
745 if (changeCount == 0)
746 return;
747 else
749 int i;
750 int target_glyph = nextIndex - write_dir;
751 int seeking_glyph;
752 int target_index = -1;
753 int replacing_glyph = -1;
754 int changed = 0;
755 int top_logclust = 0;
757 if (changeCount > 0)
759 if (write_dir > 0)
760 target_glyph = nextIndex - changeCount;
761 else
762 target_glyph = nextIndex + (changeCount + 1);
765 seeking_glyph = target_glyph;
766 for (i = 0; i < chars; i++)
767 if (pwLogClust[i] > top_logclust)
768 top_logclust = pwLogClust[i];
770 do {
771 if (write_dir > 0)
772 for (i = 0; i < chars; i++)
774 if (pwLogClust[i] == seeking_glyph)
776 target_index = i;
777 break;
780 else
781 for (i = chars - 1; i >= 0; i--)
783 if (pwLogClust[i] == seeking_glyph)
785 target_index = i;
786 break;
789 if (target_index == -1)
790 seeking_glyph ++;
792 while (target_index == -1 && seeking_glyph <= top_logclust);
794 if (target_index == -1)
796 ERR("Unable to find target glyph\n");
797 return;
800 if (changeCount < 0)
802 /* merge glyphs */
803 for(i = target_index; i < chars && i >= 0; i+=write_dir)
805 if (pwLogClust[i] == target_glyph)
806 continue;
807 if(pwLogClust[i] == replacing_glyph)
808 pwLogClust[i] = target_glyph;
809 else
811 changed--;
812 if (changed >= changeCount)
814 replacing_glyph = pwLogClust[i];
815 pwLogClust[i] = target_glyph;
817 else
818 break;
822 /* renumber trailing indexes*/
823 for(i = target_index; i < chars && i >= 0; i+=write_dir)
825 if (pwLogClust[i] != target_glyph)
826 pwLogClust[i] += changeCount;
829 else
831 for(i = target_index; i < chars && i >= 0; i+=write_dir)
832 pwLogClust[i] += changeCount;
837 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 )
839 if (psc->GSUB_Table)
841 LoadedFeature *feature;
842 int lookup_index;
844 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
845 if (!feature)
846 return GSUB_E_NOFEATURE;
848 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
849 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
851 int i;
853 if (write_dir > 0)
854 i = 0;
855 else
856 i = *pcGlyphs-1;
857 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
858 while(i < *pcGlyphs && i >= 0)
860 INT nextIndex;
861 INT prevCount = *pcGlyphs;
863 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
864 if (*pcGlyphs != prevCount)
866 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
867 i = nextIndex;
869 else
870 i+=write_dir;
873 return *pcGlyphs;
875 return GSUB_E_NOFEATURE;
878 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)
880 int i;
882 TRACE("%i lookups\n", feature->lookup_count);
883 for (i = 0; i < feature->lookup_count; i++)
885 int j;
886 for (j = 0; j < glyph_count; )
887 j = OpenType_apply_GPOS_lookup(psc, lpotm, lplogfont, analysis, piAdvance, feature->lookups[i], glyphs, j, glyph_count, pGoffset);
891 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
893 OPENTYPE_TAG tag;
894 HRESULT hr;
895 int count = 0;
897 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
899 return(SUCCEEDED(hr));
902 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
904 int i;
905 for (i = *pcGlyphs; i>=index; i--)
906 pwGlyphs[i+1] = pwGlyphs[i];
907 pwGlyphs[index] = glyph;
908 *pcGlyphs = *pcGlyphs+1;
909 if (write_dir < 0)
910 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
911 else
912 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
915 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)
917 CHAR *context_type;
918 int i,g;
919 WCHAR invalid = 0x25cc;
920 WORD invalid_glyph;
922 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
924 /* Mark invalid combinations */
925 for (i = 0; i < cChars; i++)
926 context_type[i] = lex(pwcChars[i]);
928 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
929 for (i = 1, g=1; i < cChars; i++, g++)
931 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
933 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
934 g++;
938 HeapFree(GetProcessHeap(),0,context_type);
941 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
943 if (i + delta < 0)
944 return 0;
945 if ( i+ delta >= cchLen)
946 return 0;
948 i += delta;
950 return chars[i];
953 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
955 if (i + delta < 0)
957 if (psa->fLinkBefore)
958 return jtR;
959 else
960 return jtU;
962 if ( i+ delta >= cchLen)
964 if (psa->fLinkAfter)
965 return jtL;
966 else
967 return jtU;
970 i += delta;
972 if (context_type[i] == jtT)
973 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
974 else
975 return context_type[i];
978 static inline BOOL right_join_causing(CHAR joining_type)
980 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
983 static inline BOOL left_join_causing(CHAR joining_type)
985 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
988 static inline BOOL word_break_causing(WCHAR chr)
990 /* we are working within a string of characters already guareented to
991 be within one script, Syriac, so we do not worry about any character
992 other than the space character outside of that range */
993 return (chr == 0 || chr == 0x20 );
996 static int combining_lexical_Arabic(WCHAR c)
998 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1000 switch(c)
1002 case 0x064B:
1003 case 0x064C:
1004 case 0x064E:
1005 case 0x064F:
1006 case 0x0652:
1007 case 0x0657:
1008 case 0x0658:
1009 case 0x06E1: return Arab_DIAC1;
1010 case 0x064D:
1011 case 0x0650:
1012 case 0x0656: return Arab_DIAC2;
1013 case 0x0651: return Arab_DIAC3;
1014 case 0x0610:
1015 case 0x0611:
1016 case 0x0612:
1017 case 0x0613:
1018 case 0x0614:
1019 case 0x0659:
1020 case 0x06D6:
1021 case 0x06DC:
1022 case 0x06DF:
1023 case 0x06E0:
1024 case 0x06E2:
1025 case 0x06E4:
1026 case 0x06E7:
1027 case 0x06E8:
1028 case 0x06EB:
1029 case 0x06EC: return Arab_DIAC4;
1030 case 0x06E3:
1031 case 0x06EA:
1032 case 0x06ED: return Arab_DIAC5;
1033 case 0x0670: return Arab_DIAC6;
1034 case 0x0653: return Arab_DIAC7;
1035 case 0x0655:
1036 case 0x0654: return Arab_DIAC8;
1037 default: return Arab_Norm;
1042 * ContextualShape_Arabic
1044 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1046 CHAR *context_type;
1047 INT *context_shape;
1048 INT dirR, dirL;
1049 int i;
1051 if (*pcGlyphs != cChars)
1053 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1054 return;
1057 if (!psa->fLogicalOrder && psa->fRTL)
1059 dirR = 1;
1060 dirL = -1;
1062 else
1064 dirR = -1;
1065 dirL = 1;
1068 load_ot_tables(hdc, psc);
1070 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1071 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1073 for (i = 0; i < cChars; i++)
1074 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1076 for (i = 0; i < cChars; i++)
1078 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1079 context_shape[i] = Xr;
1080 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1081 context_shape[i] = Xl;
1082 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)))
1083 context_shape[i] = Xm;
1084 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1085 context_shape[i] = Xr;
1086 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1087 context_shape[i] = Xl;
1088 else
1089 context_shape[i] = Xn;
1092 /* Contextual Shaping */
1093 i = 0;
1094 while(i < *pcGlyphs)
1096 BOOL shaped = FALSE;
1098 if (psc->GSUB_Table)
1100 INT nextIndex;
1101 INT prevCount = *pcGlyphs;
1102 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1103 if (nextIndex > GSUB_E_NOGLYPH)
1105 i = nextIndex;
1106 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1108 shaped = (nextIndex > GSUB_E_NOGLYPH);
1111 if (!shaped)
1113 if (context_shape[i] == Xn)
1115 WORD newGlyph = pwOutGlyphs[i];
1116 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1118 /* fall back to presentation form B */
1119 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1120 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1121 pwOutGlyphs[i] = newGlyph;
1124 i++;
1128 HeapFree(GetProcessHeap(),0,context_shape);
1129 HeapFree(GetProcessHeap(),0,context_type);
1131 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1134 static int combining_lexical_Hebrew(WCHAR c)
1136 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};
1138 switch(c)
1140 case 0x05B0:
1141 case 0x05B1:
1142 case 0x05B2:
1143 case 0x05B3:
1144 case 0x05B4:
1145 case 0x05B5:
1146 case 0x05B6:
1147 case 0x05BB: return Hebr_DIAC;
1148 case 0x0599:
1149 case 0x05A1:
1150 case 0x05A9:
1151 case 0x05AE: return Hebr_CANT1;
1152 case 0x0597:
1153 case 0x05A8:
1154 case 0x05AC: return Hebr_CANT2;
1155 case 0x0592:
1156 case 0x0593:
1157 case 0x0594:
1158 case 0x0595:
1159 case 0x05A7:
1160 case 0x05AB: return Hebr_CANT3;
1161 case 0x0598:
1162 case 0x059C:
1163 case 0x059E:
1164 case 0x059F: return Hebr_CANT4;
1165 case 0x059D:
1166 case 0x05A0: return Hebr_CANT5;
1167 case 0x059B:
1168 case 0x05A5: return Hebr_CANT6;
1169 case 0x0591:
1170 case 0x05A3:
1171 case 0x05A6: return Hebr_CANT7;
1172 case 0x0596:
1173 case 0x05A4:
1174 case 0x05AA: return Hebr_CANT8;
1175 case 0x059A:
1176 case 0x05AD: return Hebr_CANT9;
1177 case 0x05AF: return Hebr_CANT10;
1178 case 0x05BC: return Hebr_DAGESH;
1179 case 0x05C4: return Hebr_DOTABV;
1180 case 0x05B9: return Hebr_HOLAM;
1181 case 0x05BD: return Hebr_METEG;
1182 case 0x05B7: return Hebr_PATAH;
1183 case 0x05B8: return Hebr_QAMATS;
1184 case 0x05BF: return Hebr_RAFE;
1185 case 0x05C1:
1186 case 0x05C2: return Hebr_SHINSIN;
1187 default: return Hebr_Norm;
1191 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1193 INT dirL;
1195 if (*pcGlyphs != cChars)
1197 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1198 return;
1201 if (!psa->fLogicalOrder && psa->fRTL)
1202 dirL = -1;
1203 else
1204 dirL = 1;
1206 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1210 * ContextualShape_Syriac
1213 static int combining_lexical_Syriac(WCHAR c)
1215 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};
1217 switch(c)
1219 case 0x730:
1220 case 0x733:
1221 case 0x736:
1222 case 0x73A:
1223 case 0x73D: return Syriac_DIAC1;
1224 case 0x731:
1225 case 0x734:
1226 case 0x737:
1227 case 0x73B:
1228 case 0x73E: return Syriac_DIAC2;
1229 case 0x740:
1230 case 0x749:
1231 case 0x74A: return Syriac_DIAC3;
1232 case 0x732:
1233 case 0x735:
1234 case 0x73F: return Syriac_DIAC4;
1235 case 0x738:
1236 case 0x739:
1237 case 0x73C: return Syriac_DIAC5;
1238 case 0x741:
1239 case 0x30A: return Syriac_DIAC6;
1240 case 0x742:
1241 case 0x325: return Syriac_DIAC7;
1242 case 0x747:
1243 case 0x303: return Syriac_DIAC8;
1244 case 0x748:
1245 case 0x32D:
1246 case 0x32E:
1247 case 0x330:
1248 case 0x331: return Syriac_DIAC9;
1249 case 0x308: return Syriac_DIAC10;
1250 case 0x304: return Syriac_DIAC11;
1251 case 0x307: return Syriac_DIAC12;
1252 case 0x323: return Syriac_DIAC13;
1253 case 0x743: return Syriac_DIAC14;
1254 case 0x744: return Syriac_DIAC15;
1255 case 0x745: return Syriac_DIAC16;
1256 case 0x746: return Syriac_DIAC17;
1257 default: return Syriac_Norm;
1261 #define ALAPH 0x710
1262 #define DALATH 0x715
1263 #define RISH 0x72A
1265 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1267 CHAR *context_type;
1268 INT *context_shape;
1269 INT dirR, dirL;
1270 int i;
1272 if (*pcGlyphs != cChars)
1274 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1275 return;
1278 if (!psa->fLogicalOrder && psa->fRTL)
1280 dirR = 1;
1281 dirL = -1;
1283 else
1285 dirR = -1;
1286 dirL = 1;
1289 load_ot_tables(hdc, psc);
1291 if (!psc->GSUB_Table)
1292 return;
1294 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1295 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1297 for (i = 0; i < cChars; i++)
1298 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1300 for (i = 0; i < cChars; i++)
1302 if (pwcChars[i] == ALAPH)
1304 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1306 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1307 context_shape[i] = Afj;
1308 else if ( rchar != DALATH && rchar != RISH &&
1309 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1310 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1311 context_shape[i] = Afn;
1312 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1313 context_shape[i] = Afx;
1314 else
1315 context_shape[i] = Xn;
1317 else if (context_type[i] == jtR &&
1318 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1319 context_shape[i] = Xr;
1320 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1321 context_shape[i] = Xl;
1322 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)))
1323 context_shape[i] = Xm;
1324 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1325 context_shape[i] = Xr;
1326 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1327 context_shape[i] = Xl;
1328 else
1329 context_shape[i] = Xn;
1332 /* Contextual Shaping */
1333 i = 0;
1334 while(i < *pcGlyphs)
1336 INT nextIndex;
1337 INT prevCount = *pcGlyphs;
1338 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1339 if (nextIndex > GSUB_E_NOGLYPH)
1341 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1342 i = nextIndex;
1344 else
1345 i++;
1348 HeapFree(GetProcessHeap(),0,context_shape);
1349 HeapFree(GetProcessHeap(),0,context_type);
1351 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1354 static int combining_lexical_Thaana(WCHAR c)
1356 enum {Thaana_Norm=0, Thaana_FILI};
1358 switch(c)
1360 case 0x7A6:
1361 case 0x7A7:
1362 case 0x7A8:
1363 case 0x7A9:
1364 case 0x7AA:
1365 case 0x7AB:
1366 case 0x7AC:
1367 case 0x7AD:
1368 case 0x7AE:
1369 case 0x7AF: return Thaana_FILI;
1370 default: return Thaana_Norm;
1374 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1376 INT dirL;
1378 if (*pcGlyphs != cChars)
1380 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1381 return;
1384 if (!psa->fLogicalOrder && psa->fRTL)
1385 dirL = -1;
1386 else
1387 dirL = 1;
1389 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1393 * ContextualShape_Phags_pa
1396 #define phags_pa_CANDRABINDU 0xA873
1397 #define phags_pa_START 0xA840
1398 #define phags_pa_END 0xA87F
1400 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1402 INT *context_shape;
1403 INT dirR, dirL;
1404 int i;
1406 if (*pcGlyphs != cChars)
1408 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1409 return;
1412 if (!psa->fLogicalOrder && psa->fRTL)
1414 dirR = 1;
1415 dirL = -1;
1417 else
1419 dirR = -1;
1420 dirL = 1;
1423 load_ot_tables(hdc, psc);
1425 if (!psc->GSUB_Table)
1426 return;
1428 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1430 for (i = 0; i < cChars; i++)
1432 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1434 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1435 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1436 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1437 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1439 if (jrchar && jlchar)
1440 context_shape[i] = Xm;
1441 else if (jrchar)
1442 context_shape[i] = Xr;
1443 else if (jlchar)
1444 context_shape[i] = Xl;
1445 else
1446 context_shape[i] = Xn;
1448 else
1449 context_shape[i] = -1;
1452 /* Contextual Shaping */
1453 i = 0;
1454 while(i < *pcGlyphs)
1456 if (context_shape[i] >= 0)
1458 INT nextIndex;
1459 INT prevCount = *pcGlyphs;
1460 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1461 if (nextIndex > GSUB_E_NOGLYPH)
1463 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1464 i = nextIndex;
1466 else
1467 i++;
1469 else
1470 i++;
1473 HeapFree(GetProcessHeap(),0,context_shape);
1476 static int combining_lexical_Thai(WCHAR c)
1478 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1480 switch(c)
1482 case 0xE31:
1483 case 0xE34:
1484 case 0xE35:
1485 case 0xE36:
1486 case 0xE37: return Thai_ABOVE1;
1487 case 0xE47:
1488 case 0xE4D: return Thai_ABOVE2;
1489 case 0xE48:
1490 case 0xE49:
1491 case 0xE4A:
1492 case 0xE4B: return Thai_ABOVE3;
1493 case 0xE4C:
1494 case 0xE4E: return Thai_ABOVE4;
1495 case 0xE38:
1496 case 0xE39: return Thai_BELOW1;
1497 case 0xE3A: return Thai_BELOW2;
1498 case 0xE33: return Thai_AM;
1499 default: return Thai_Norm;
1503 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1505 INT dirL;
1507 if (*pcGlyphs != cChars)
1509 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1510 return;
1513 if (!psa->fLogicalOrder && psa->fRTL)
1514 dirL = -1;
1515 else
1516 dirL = 1;
1518 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1521 static int combining_lexical_Lao(WCHAR c)
1523 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1525 switch(c)
1527 case 0xEB1:
1528 case 0xEB4:
1529 case 0xEB5:
1530 case 0xEB6:
1531 case 0xEB7:
1532 case 0xEBB:
1533 case 0xECD: return Lao_ABOVE1;
1534 case 0xEC8:
1535 case 0xEC9:
1536 case 0xECA:
1537 case 0xECB:
1538 case 0xECC: return Lao_ABOVE2;
1539 case 0xEBC: return Lao_BELOW1;
1540 case 0xEB8:
1541 case 0xEB9: return Lao_BELOW2;
1542 case 0xEB3: return Lao_AM;
1543 default: return Lao_Norm;
1547 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1549 INT dirL;
1551 if (*pcGlyphs != cChars)
1553 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1554 return;
1557 if (!psa->fLogicalOrder && psa->fRTL)
1558 dirL = -1;
1559 else
1560 dirL = 1;
1562 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1565 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1567 int i;
1569 /* Replace */
1570 pwOutChars[cWalk] = replacements[0];
1571 cWalk=cWalk+1;
1573 /* Insert */
1574 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1576 int j;
1577 for (j = *pcChars; j > cWalk; j--)
1578 pwOutChars[j] = pwOutChars[j-1];
1579 *pcChars= *pcChars+1;
1580 pwOutChars[cWalk] = replacements[i];
1581 cWalk = cWalk+1;
1585 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1587 int i;
1588 int cWalk;
1590 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1592 for (i = 0; vowels[i].base != 0x0; i++)
1594 if (pwOutChars[cWalk] == vowels[i].base)
1596 int o = 0;
1597 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1598 if (vowels[i].parts[1]) { cWalk++; o++; }
1599 if (vowels[i].parts[2]) { cWalk++; o++; }
1600 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1601 break;
1607 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1609 int i;
1610 int offset = 0;
1611 int cWalk;
1613 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1615 for (i = 0; consonants[i].output!= 0x0; i++)
1617 int j;
1618 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1619 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1620 break;
1622 if (consonants[i].parts[j]==0x0) /* matched all */
1624 int k;
1625 j--;
1626 pwOutChars[cWalk] = consonants[i].output;
1627 for(k = cWalk+1; k < *pcChars - j; k++)
1628 pwOutChars[k] = pwOutChars[k+j];
1629 *pcChars = *pcChars - j;
1630 for (k = j ; k > 0; k--)
1631 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1632 offset += j;
1633 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1634 pwLogClust[k]--;
1635 break;
1638 cWalk++;
1642 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1644 if (s->ralf >= 0)
1646 int j;
1647 WORD Ra = pwChar[s->start];
1648 WORD H = pwChar[s->start+1];
1650 TRACE("Doing reorder of Ra to %i\n",s->base);
1651 for (j = s->start; j < s->base-1; j++)
1652 pwChar[j] = pwChar[j+2];
1653 pwChar[s->base-1] = Ra;
1654 pwChar[s->base] = H;
1656 s->ralf = s->base-1;
1657 s->base -= 2;
1661 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1663 if (s->ralf >= 0)
1665 int j,loc;
1666 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1667 WORD Ra = pwChar[s->start];
1668 WORD H = pwChar[s->start+1];
1669 for (loc = s->end; loc > stop; loc--)
1670 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1671 break;
1673 TRACE("Doing reorder of Ra to %i\n",loc);
1674 for (j = s->start; j < loc-1; j++)
1675 pwChar[j] = pwChar[j+2];
1676 pwChar[loc-1] = Ra;
1677 pwChar[loc] = H;
1679 s->ralf = loc-1;
1680 s->base -= 2;
1681 if (s->blwf >= 0) s->blwf -= 2;
1682 if (s->pref >= 0) s->pref -= 2;
1686 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1688 if (s->ralf >= 0)
1690 int j;
1691 WORD Ra = pwChar[s->start];
1692 WORD H = pwChar[s->start+1];
1694 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1695 for (j = s->start; j < s->end-1; j++)
1696 pwChar[j] = pwChar[j+2];
1697 pwChar[s->end-1] = Ra;
1698 pwChar[s->end] = H;
1700 s->ralf = s->end-1;
1701 s->base -= 2;
1702 if (s->blwf >= 0) s->blwf -= 2;
1703 if (s->pref >= 0) s->pref -= 2;
1707 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1709 int i;
1711 /* reorder Matras */
1712 if (s->end > s->base)
1714 for (i = 1; i <= s->end-s->base; i++)
1716 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1718 int j;
1719 WCHAR c = pwChar[s->base+i];
1720 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1721 for (j = s->base+i; j > s->base; j--)
1722 pwChar[j] = pwChar[j-1];
1723 pwChar[s->base] = c;
1725 if (s->ralf >= s->base) s->ralf++;
1726 if (s->blwf >= s->base) s->blwf++;
1727 if (s->pref >= s->base) s->pref++;
1728 s->base ++;
1734 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1736 int i;
1738 /* reorder Matras */
1739 if (s->end > s->base)
1741 for (i = 1; i <= s->end-s->base; i++)
1743 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1745 int j;
1746 WCHAR c = pwChar[s->base+i];
1747 TRACE("Doing reorder of %x to %i\n",c,s->start);
1748 for (j = s->base+i; j > s->start; j--)
1749 pwChar[j] = pwChar[j-1];
1750 pwChar[s->start] = c;
1752 if (s->ralf >= 0) s->ralf++;
1753 if (s->blwf >= 0) s->blwf++;
1754 if (s->pref >= 0) s->pref++;
1755 s->base ++;
1761 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1763 if (s->blwf >= 0 && g->blwf > g->base)
1765 int j,loc;
1766 int g_offset;
1767 for (loc = s->end; loc > s->blwf; loc--)
1768 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1769 break;
1771 g_offset = (loc - s->blwf) - 1;
1773 if (loc != s->blwf)
1775 WORD blwf = glyphs[g->blwf];
1776 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1777 /* do not care about the pwChar array anymore, just the glyphs */
1778 for (j = 0; j < g_offset; j++)
1779 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1780 glyphs[g->blwf + g_offset] = blwf;
1785 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1787 int i;
1789 /* reorder previously moved Matras to correct position*/
1790 for (i = s->start; i < s->base; i++)
1792 if (lexical(pwChar[i]) == lex_Matra_pre)
1794 int j;
1795 int g_start = g->start + i - s->start;
1796 if (g_start < g->base -1 )
1798 WCHAR og = glyphs[g_start];
1799 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1800 for (j = g_start; j < g->base-1; j++)
1801 glyphs[j] = glyphs[j+1];
1802 glyphs[g->base-1] = og;
1808 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1810 if (s->pref >= 0 && g->pref > g->base)
1812 int j;
1813 WCHAR og = glyphs[g->pref];
1814 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1815 for (j = g->pref; j > g->base; j--)
1816 glyphs[j] = glyphs[j-1];
1817 glyphs[g->base] = og;
1821 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1823 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1824 if (s->start == s->base && s->base == s->end) return;
1825 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1827 Reorder_Ra_follows_base(pwChar, s, lexical);
1828 Reorder_Matra_precede_base(pwChar, s, lexical);
1831 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1833 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1834 if (s->start == s->base && s->base == s->end) return;
1835 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1837 Reorder_Ra_follows_matra(pwChar, s, lexical);
1838 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1841 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1843 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1844 if (s->start == s->base && s->base == s->end) return;
1845 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1847 Reorder_Ra_follows_base(pwChar, s, lexical);
1848 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1851 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1853 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1854 if (s->start == s->base && s->base == s->end) return;
1855 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1857 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1858 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1861 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1863 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1864 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1865 if (s->start == s->base && s->base == s->end) return;
1866 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1868 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1871 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1873 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1874 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1875 if (s->start == s->base && s->base == s->end) return;
1876 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1878 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1879 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1883 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1885 if (shift == 0)
1886 return;
1888 if (glyph_index->start > index)
1889 glyph_index->start += shift;
1890 if (glyph_index->base > index)
1891 glyph_index->base+= shift;
1892 if (glyph_index->end > index)
1893 glyph_index->end+= shift;
1894 if (glyph_index->ralf > index)
1895 glyph_index->ralf+= shift;
1896 if (glyph_index->blwf > index)
1897 glyph_index->blwf+= shift;
1898 if (glyph_index->pref > index)
1899 glyph_index->pref+= shift;
1902 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 )
1904 int index = glyph_index->start;
1906 if (!feature)
1907 return;
1909 while(index <= glyph_index->end)
1911 INT nextIndex;
1912 INT prevCount = *pcGlyphs;
1913 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1914 if (nextIndex > GSUB_E_NOGLYPH)
1916 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1917 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1918 index = nextIndex;
1920 else
1921 index++;
1925 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1927 int i = 0;
1928 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)))))
1929 i++;
1930 if (index + i <= end-1)
1931 return index + i;
1932 else
1933 return -1;
1936 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)
1938 INT index, nextIndex;
1939 INT count,g_offset;
1941 count = syllable->base - syllable->start;
1943 g_offset = 0;
1944 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1945 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1947 INT prevCount = *pcGlyphs;
1948 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1949 if (nextIndex > GSUB_E_NOGLYPH)
1951 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1952 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1953 g_offset += (*pcGlyphs - prevCount);
1956 index+=2;
1957 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1961 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)
1963 INT nextIndex;
1964 INT prevCount = *pcGlyphs;
1966 if (syllable->ralf >= 0)
1968 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1969 if (nextIndex > GSUB_E_NOGLYPH)
1971 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1972 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1977 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1979 int i = 0;
1980 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1981 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1982 is_consonant(lexical(pwChars[index+i+1])))))
1983 i++;
1984 if (index + i <= end-1)
1985 return index+i;
1986 else
1987 return -1;
1990 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)
1992 INT index, nextIndex;
1993 INT count, g_offset=0;
1994 INT ralf = syllable->ralf;
1996 count = syllable->end - syllable->base;
1998 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2000 while (index >= 0)
2002 INT prevCount = *pcGlyphs;
2003 if (ralf >=0 && ralf < index)
2005 g_offset--;
2006 ralf = -1;
2009 if (!modern)
2011 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2012 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2013 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2016 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2017 if (nextIndex > GSUB_E_NOGLYPH)
2019 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2020 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2021 g_offset += (*pcGlyphs - prevCount);
2023 else if (!modern)
2025 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2026 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2027 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2030 index+=2;
2031 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2035 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)
2037 int c;
2038 int overall_shift = 0;
2039 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2040 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2041 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2042 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2043 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2044 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2045 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2046 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2047 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2048 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2049 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2050 IndicSyllable glyph_indexs;
2052 for (c = 0; c < syllable_count; c++)
2054 int old_end;
2055 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2056 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2057 old_end = glyph_indexs.end;
2059 if (locl)
2061 TRACE("applying feature locl\n");
2062 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2064 if (nukt)
2066 TRACE("applying feature nukt\n");
2067 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2069 if (akhn)
2071 TRACE("applying feature akhn\n");
2072 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2075 if (rphf)
2076 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2077 if (rkrf)
2079 TRACE("applying feature rkrf\n");
2080 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2082 if (pref)
2083 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2084 if (blwf)
2086 if (!modern)
2087 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2089 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2092 if (half)
2093 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2094 if (pstf)
2096 TRACE("applying feature pstf\n");
2097 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2099 if (vatu)
2101 TRACE("applying feature vatu\n");
2102 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2104 if (cjct)
2106 TRACE("applying feature cjct\n");
2107 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2110 if (second_reorder)
2111 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2113 overall_shift += glyph_indexs.end - old_end;
2117 static inline int unicode_lex(WCHAR c)
2119 int type;
2121 if (!c) return lex_Generic;
2122 if (c == 0x200D) return lex_ZWJ;
2123 if (c == 0x200C) return lex_ZWNJ;
2124 if (c == 0x00A0) return lex_NBSP;
2126 type = get_table_entry( indic_syllabic_table, c );
2128 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2130 switch( type )
2132 case 0x0d07: /* Unknown */
2133 case 0x0e07: /* Unknwon */
2134 default: return lex_Generic;
2135 case 0x0001:
2136 case 0x0002:
2137 case 0x0011:
2138 case 0x0012:
2139 case 0x0013:
2140 case 0x0014: return lex_Modifier;
2141 case 0x0003:
2142 case 0x0009:
2143 case 0x000a:
2144 case 0x000b:
2145 case 0x000d:
2146 case 0x000e:
2147 case 0x000f:
2148 case 0x0010: return lex_Consonant;
2149 case 0x0004: return lex_Nukta;
2150 case 0x0005: return lex_Halant;
2151 case 0x0006:
2152 case 0x0008: return lex_Vowel;
2153 case 0x0007:
2154 case 0x0107: return lex_Matra_post;
2155 case 0x0207:
2156 case 0x0307: return lex_Matra_pre;
2157 case 0x0807:
2158 case 0x0907:
2159 case 0x0a07:
2160 case 0x0b07:
2161 case 0x0c07:
2162 case 0x0407: return lex_Composed_Vowel;
2163 case 0x0507: return lex_Matra_above;
2164 case 0x0607: return lex_Matra_below;
2165 case 0x000c: return lex_Ra;
2169 static int sinhala_lex(WCHAR c)
2171 switch (c)
2173 case 0x0DDA:
2174 case 0x0DDD:
2175 case 0x0DDC:
2176 case 0x0DDE: return lex_Matra_post;
2177 default:
2178 return unicode_lex(c);
2182 static const VowelComponents Sinhala_vowels[] = {
2183 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2184 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2185 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2186 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2187 {0x0000, {0x0000,0x0000,0x0}}};
2189 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2191 int cCount = cChars;
2192 int i;
2193 WCHAR *input;
2194 IndicSyllable *syllables = NULL;
2195 int syllable_count = 0;
2197 if (*pcGlyphs != cChars)
2199 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2200 return;
2203 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2205 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2207 /* Step 1: Decompose multi part vowels */
2208 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2210 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2212 /* Step 2: Reorder within Syllables */
2213 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2214 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2216 /* Step 3: Strip dangling joiners */
2217 for (i = 0; i < cCount; i++)
2219 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2220 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2221 input[i] = 0x0020;
2224 /* Step 4: Base Form application to syllables */
2225 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2226 *pcGlyphs = cCount;
2227 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2229 HeapFree(GetProcessHeap(),0,input);
2230 HeapFree(GetProcessHeap(),0,syllables);
2233 static int devanagari_lex(WCHAR c)
2235 switch (c)
2237 case 0x0930: return lex_Ra;
2238 default:
2239 return unicode_lex(c);
2243 static const ConsonantComponents Devanagari_consonants[] ={
2244 {{0x0928, 0x093C, 0x00000}, 0x0929},
2245 {{0x0930, 0x093C, 0x00000}, 0x0931},
2246 {{0x0933, 0x093C, 0x00000}, 0x0934},
2247 {{0x0915, 0x093C, 0x00000}, 0x0958},
2248 {{0x0916, 0x093C, 0x00000}, 0x0959},
2249 {{0x0917, 0x093C, 0x00000}, 0x095A},
2250 {{0x091C, 0x093C, 0x00000}, 0x095B},
2251 {{0x0921, 0x093C, 0x00000}, 0x095C},
2252 {{0x0922, 0x093C, 0x00000}, 0x095D},
2253 {{0x092B, 0x093C, 0x00000}, 0x095E},
2254 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2256 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2258 int cCount = cChars;
2259 WCHAR *input;
2260 IndicSyllable *syllables = NULL;
2261 int syllable_count = 0;
2262 BOOL modern = get_GSUB_Indic2(psa, psc);
2264 if (*pcGlyphs != cChars)
2266 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2267 return;
2270 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2271 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2273 /* Step 1: Compose Consonant and Nukta */
2274 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2275 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2277 /* Step 2: Reorder within Syllables */
2278 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2279 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2280 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2281 *pcGlyphs = cCount;
2283 /* Step 3: Base Form application to syllables */
2284 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2286 HeapFree(GetProcessHeap(),0,input);
2287 HeapFree(GetProcessHeap(),0,syllables);
2290 static int bengali_lex(WCHAR c)
2292 switch (c)
2294 case 0x09B0: return lex_Ra;
2295 default:
2296 return unicode_lex(c);
2300 static const VowelComponents Bengali_vowels[] = {
2301 {0x09CB, {0x09C7,0x09BE,0x0000}},
2302 {0x09CC, {0x09C7,0x09D7,0x0000}},
2303 {0x0000, {0x0000,0x0000,0x0000}}};
2305 static const ConsonantComponents Bengali_consonants[] = {
2306 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2307 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2308 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2309 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2310 {{0x0000,0x0000,0x0000}, 0x0000}};
2312 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2314 int cCount = cChars;
2315 WCHAR *input;
2316 IndicSyllable *syllables = NULL;
2317 int syllable_count = 0;
2318 BOOL modern = get_GSUB_Indic2(psa, psc);
2320 if (*pcGlyphs != cChars)
2322 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2323 return;
2326 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2327 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2329 /* Step 1: Decompose Vowels and Compose Consonants */
2330 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2331 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2332 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2334 /* Step 2: Reorder within Syllables */
2335 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2336 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2337 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2338 *pcGlyphs = cCount;
2340 /* Step 3: Initial form is only applied to the beginning of words */
2341 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2343 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2345 int index = cCount;
2346 int gCount = 1;
2347 if (index > 0) index++;
2349 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2353 /* Step 4: Base Form application to syllables */
2354 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2356 HeapFree(GetProcessHeap(),0,input);
2357 HeapFree(GetProcessHeap(),0,syllables);
2360 static int gurmukhi_lex(WCHAR c)
2362 if (c == 0x0A71)
2363 return lex_Modifier;
2364 else
2365 return unicode_lex(c);
2368 static const ConsonantComponents Gurmukhi_consonants[] = {
2369 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2370 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2371 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2372 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2373 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2374 {{0x0000,0x0000,0x0000}, 0x0000}};
2376 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2378 int cCount = cChars;
2379 WCHAR *input;
2380 IndicSyllable *syllables = NULL;
2381 int syllable_count = 0;
2382 BOOL modern = get_GSUB_Indic2(psa, psc);
2384 if (*pcGlyphs != cChars)
2386 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2387 return;
2390 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2391 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2393 /* Step 1: Compose Consonants */
2394 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2395 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2397 /* Step 2: Reorder within Syllables */
2398 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2399 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2400 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2401 *pcGlyphs = cCount;
2403 /* Step 3: Base Form application to syllables */
2404 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2406 HeapFree(GetProcessHeap(),0,input);
2407 HeapFree(GetProcessHeap(),0,syllables);
2410 static int gujarati_lex(WCHAR c)
2412 switch (c)
2414 case 0x0AB0: return lex_Ra;
2415 default:
2416 return unicode_lex(c);
2420 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2422 int cCount = cChars;
2423 WCHAR *input;
2424 IndicSyllable *syllables = NULL;
2425 int syllable_count = 0;
2426 BOOL modern = get_GSUB_Indic2(psa, psc);
2428 if (*pcGlyphs != cChars)
2430 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2431 return;
2434 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2435 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2437 /* Step 1: Reorder within Syllables */
2438 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2439 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2440 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2441 *pcGlyphs = cCount;
2443 /* Step 2: Base Form application to syllables */
2444 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2446 HeapFree(GetProcessHeap(),0,input);
2447 HeapFree(GetProcessHeap(),0,syllables);
2450 static int oriya_lex(WCHAR c)
2452 switch (c)
2454 case 0x0B30: return lex_Ra;
2455 default:
2456 return unicode_lex(c);
2460 static const VowelComponents Oriya_vowels[] = {
2461 {0x0B48, {0x0B47,0x0B56,0x0000}},
2462 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2463 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2464 {0x0000, {0x0000,0x0000,0x0000}}};
2466 static const ConsonantComponents Oriya_consonants[] = {
2467 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2468 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2469 {{0x0000,0x0000,0x0000}, 0x0000}};
2471 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2473 int cCount = cChars;
2474 WCHAR *input;
2475 IndicSyllable *syllables = NULL;
2476 int syllable_count = 0;
2477 BOOL modern = get_GSUB_Indic2(psa, psc);
2479 if (*pcGlyphs != cChars)
2481 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2482 return;
2485 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2486 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2488 /* Step 1: Decompose Vowels and Compose Consonants */
2489 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2490 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2491 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2493 /* Step 2: Reorder within Syllables */
2494 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2495 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2496 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2497 *pcGlyphs = cCount;
2499 /* Step 3: Base Form application to syllables */
2500 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2502 HeapFree(GetProcessHeap(),0,input);
2503 HeapFree(GetProcessHeap(),0,syllables);
2506 static int tamil_lex(WCHAR c)
2508 return unicode_lex(c);
2511 static const VowelComponents Tamil_vowels[] = {
2512 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2513 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2514 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2515 {0x0000, {0x0000,0x0000,0x0000}}};
2517 static const ConsonantComponents Tamil_consonants[] = {
2518 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2519 {{0x0000,0x0000,0x0000}, 0x0000}};
2521 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2523 int cCount = cChars;
2524 WCHAR *input;
2525 IndicSyllable *syllables = NULL;
2526 int syllable_count = 0;
2527 BOOL modern = get_GSUB_Indic2(psa, psc);
2529 if (*pcGlyphs != cChars)
2531 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2532 return;
2535 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2536 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2538 /* Step 1: Decompose Vowels and Compose Consonants */
2539 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2540 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2541 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2543 /* Step 2: Reorder within Syllables */
2544 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2545 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2546 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2547 *pcGlyphs = cCount;
2549 /* Step 3: Base Form application to syllables */
2550 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2552 HeapFree(GetProcessHeap(),0,input);
2553 HeapFree(GetProcessHeap(),0,syllables);
2556 static int telugu_lex(WCHAR c)
2558 switch (c)
2560 case 0x0C43:
2561 case 0x0C44: return lex_Modifier;
2562 default:
2563 return unicode_lex(c);
2567 static const VowelComponents Telugu_vowels[] = {
2568 {0x0C48, {0x0C46,0x0C56,0x0000}},
2569 {0x0000, {0x0000,0x0000,0x0000}}};
2571 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2573 int cCount = cChars;
2574 WCHAR *input;
2575 IndicSyllable *syllables = NULL;
2576 int syllable_count = 0;
2577 BOOL modern = get_GSUB_Indic2(psa, psc);
2579 if (*pcGlyphs != cChars)
2581 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2582 return;
2585 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2586 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2588 /* Step 1: Decompose Vowels */
2589 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2590 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2592 /* Step 2: Reorder within Syllables */
2593 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2594 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2595 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2596 *pcGlyphs = cCount;
2598 /* Step 3: Base Form application to syllables */
2599 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2601 HeapFree(GetProcessHeap(),0,input);
2602 HeapFree(GetProcessHeap(),0,syllables);
2605 static int kannada_lex(WCHAR c)
2607 switch (c)
2609 case 0x0CB0: return lex_Ra;
2610 default:
2611 return unicode_lex(c);
2615 static const VowelComponents Kannada_vowels[] = {
2616 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2617 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2618 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2619 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2620 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2621 {0x0000, {0x0000,0x0000,0x0000}}};
2623 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2625 int cCount = cChars;
2626 WCHAR *input;
2627 IndicSyllable *syllables = NULL;
2628 int syllable_count = 0;
2629 BOOL modern = get_GSUB_Indic2(psa, psc);
2631 if (*pcGlyphs != cChars)
2633 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2634 return;
2637 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2638 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2640 /* Step 1: Decompose Vowels */
2641 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2642 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2644 /* Step 2: Reorder within Syllables */
2645 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2646 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2647 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2648 *pcGlyphs = cCount;
2650 /* Step 3: Base Form application to syllables */
2651 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2653 HeapFree(GetProcessHeap(),0,input);
2654 HeapFree(GetProcessHeap(),0,syllables);
2657 static int malayalam_lex(WCHAR c)
2659 return unicode_lex(c);
2662 static const VowelComponents Malayalam_vowels[] = {
2663 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2664 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2665 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2666 {0x0000, {0x0000,0x0000,0x0000}}};
2668 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2670 int cCount = cChars;
2671 WCHAR *input;
2672 IndicSyllable *syllables = NULL;
2673 int syllable_count = 0;
2674 BOOL modern = get_GSUB_Indic2(psa, psc);
2676 if (*pcGlyphs != cChars)
2678 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2679 return;
2682 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2683 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2685 /* Step 1: Decompose Vowels */
2686 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2687 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2689 /* Step 2: Reorder within Syllables */
2690 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2691 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2692 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2693 *pcGlyphs = cCount;
2695 /* Step 3: Base Form application to syllables */
2696 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2698 HeapFree(GetProcessHeap(),0,input);
2699 HeapFree(GetProcessHeap(),0,syllables);
2702 static int khmer_lex(WCHAR c)
2704 return unicode_lex(c);
2707 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2709 int cCount = cChars;
2710 WCHAR *input;
2711 IndicSyllable *syllables = NULL;
2712 int syllable_count = 0;
2714 if (*pcGlyphs != cChars)
2716 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2717 return;
2720 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2721 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2723 /* Step 1: Reorder within Syllables */
2724 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2725 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2726 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2727 *pcGlyphs = cCount;
2729 /* Step 2: Base Form application to syllables */
2730 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2732 HeapFree(GetProcessHeap(),0,input);
2733 HeapFree(GetProcessHeap(),0,syllables);
2736 static inline BOOL mongolian_wordbreak(WCHAR chr)
2738 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2741 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2743 INT *context_shape;
2744 INT dirL;
2745 int i;
2747 if (*pcGlyphs != cChars)
2749 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2750 return;
2753 if (!psa->fLogicalOrder && psa->fRTL)
2754 dirL = -1;
2755 else
2756 dirL = 1;
2758 if (!psc->GSUB_Table)
2759 return;
2761 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2763 for (i = 0; i < cChars; i++)
2765 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2767 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2768 context_shape[i] = Xn;
2769 else
2770 context_shape[i] = Xl;
2772 else
2774 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2775 context_shape[i] = Xr;
2776 else
2777 context_shape[i] = Xm;
2781 /* Contextual Shaping */
2782 i = 0;
2783 while(i < *pcGlyphs)
2785 INT nextIndex;
2786 INT prevCount = *pcGlyphs;
2787 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2788 if (nextIndex > GSUB_E_NOGLYPH)
2790 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2791 i = nextIndex;
2793 else
2794 i++;
2797 HeapFree(GetProcessHeap(),0,context_shape);
2800 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)
2802 int i,k;
2804 for (i = 0; i < cGlyphs; i++)
2806 int char_index[20];
2807 int char_count = 0;
2809 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2810 if (k>=0)
2812 for (; k < cChars && pwLogClust[k] == i; k++)
2813 char_index[char_count++] = k;
2816 if (char_count == 0)
2817 continue;
2819 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2821 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2822 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2824 else
2825 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2828 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2829 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2832 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 )
2834 int i,k;
2835 int initGlyph, finaGlyph;
2836 INT dirR, dirL;
2837 BYTE *spaces;
2839 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2840 memset(spaces,0,cGlyphs);
2842 if (!psa->fLogicalOrder && psa->fRTL)
2844 initGlyph = cGlyphs-1;
2845 finaGlyph = 0;
2846 dirR = 1;
2847 dirL = -1;
2849 else
2851 initGlyph = 0;
2852 finaGlyph = cGlyphs-1;
2853 dirR = -1;
2854 dirL = 1;
2857 for (i = 0; i < cGlyphs; i++)
2859 for (k = 0; k < cChars; k++)
2860 if (pwLogClust[k] == i)
2862 if (pwcChars[k] == 0x0020)
2863 spaces[i] = 1;
2867 for (i = 0; i < cGlyphs; i++)
2869 int char_index[20];
2870 int char_count = 0;
2871 BOOL isInit, isFinal;
2873 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2874 if (k>=0)
2876 for (; k < cChars && pwLogClust[k] == i; k++)
2877 char_index[char_count++] = k;
2880 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2881 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2883 if (char_count == 0)
2884 continue;
2886 if (char_count == 1)
2888 if (pwcChars[char_index[0]] == 0x0020) /* space */
2890 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2891 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2893 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2894 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2895 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2897 if (!isInit && !isFinal)
2898 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2899 else if (isInit)
2900 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2901 else
2902 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2904 else if (!isInit)
2906 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2907 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2908 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2909 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2910 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2911 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2912 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2913 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2914 else
2915 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2917 else if (!isInit && !isFinal)
2918 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2919 else
2920 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2922 else if (char_count == 2)
2924 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2925 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2926 else if (!isInit)
2927 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
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;
2937 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2938 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2939 HeapFree(GetProcessHeap(),0,spaces);
2942 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 )
2944 int i,k;
2946 for (i = 0; i < cGlyphs; i++)
2948 int char_index[20];
2949 int char_count = 0;
2951 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2952 if (k>=0)
2954 for (; k < cChars && pwLogClust[k] == i; k++)
2955 char_index[char_count++] = k;
2958 if (char_count == 0)
2959 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2960 else
2962 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2963 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2964 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2968 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2969 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2972 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 )
2974 int i;
2975 int finaGlyph;
2976 INT dirL;
2978 if (!psa->fLogicalOrder && psa->fRTL)
2980 finaGlyph = 0;
2981 dirL = -1;
2983 else
2985 finaGlyph = cGlyphs-1;
2986 dirL = 1;
2989 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2991 for (i = 0; i < cGlyphs; i++)
2993 int k;
2994 int char_index[20];
2995 int char_count = 0;
2997 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2998 if (k>=0)
3000 for (; k < cChars && pwLogClust[k] == i; k++)
3001 char_index[char_count++] = k;
3004 if (i == finaGlyph)
3005 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3006 else
3007 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3009 if (char_count == 0)
3010 continue;
3012 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3013 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3015 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3016 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3017 pGlyphProp[i].sva.fClusterStart = 0;
3020 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3022 /* Do not allow justification between marks and their base */
3023 for (i = 0; i < cGlyphs; i++)
3025 if (!pGlyphProp[i].sva.fClusterStart)
3026 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3030 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)
3032 int i,k;
3034 for (i = 0; i < cGlyphs; i++)
3036 int char_index[20];
3037 int char_count = 0;
3039 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3040 if (k>=0)
3042 for (; k < cChars && pwLogClust[k] == i; k++)
3043 char_index[char_count++] = k;
3046 if (char_count == 0)
3047 continue;
3049 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3051 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3052 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3054 else
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3057 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3058 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3061 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)
3063 int i,k;
3065 for (i = 0; i < cGlyphs; i++)
3067 int char_index[20];
3068 int char_count = 0;
3070 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3071 if (k>=0)
3073 for (; k < cChars && pwLogClust[k] == i; k++)
3074 char_index[char_count++] = k;
3077 if (char_count == 0)
3078 continue;
3080 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3082 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3083 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3085 else
3086 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3088 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3089 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3091 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3092 for (i = 0; i < cGlyphs; i++)
3094 if (!pGlyphProp[i].sva.fClusterStart)
3096 pGlyphProp[i].sva.fDiacritic = 0;
3097 pGlyphProp[i].sva.fZeroWidth = 0;
3102 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)
3104 int i,k;
3106 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3107 for (i = 0; i < cGlyphs; i++)
3109 int char_index[20];
3110 int char_count = 0;
3112 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3113 if (k>=0)
3115 for (; k < cChars && pwLogClust[k] == i; k++)
3116 char_index[char_count++] = k;
3119 if (override_gsub)
3121 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3122 pGlyphProp[i].sva.fDiacritic = FALSE;
3123 pGlyphProp[i].sva.fZeroWidth = FALSE;
3126 if (char_count == 0)
3128 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3129 continue;
3132 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3134 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3135 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3137 else
3138 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3140 pGlyphProp[i].sva.fClusterStart = 0;
3141 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3142 switch (lexical(pwcChars[char_index[k]]))
3144 case lex_Matra_pre:
3145 case lex_Matra_post:
3146 case lex_Matra_above:
3147 case lex_Matra_below:
3148 case lex_Modifier:
3149 case lex_Halant:
3150 break;
3151 case lex_ZWJ:
3152 case lex_ZWNJ:
3153 /* check for dangling joiners */
3154 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3155 pGlyphProp[i].sva.fClusterStart = 1;
3156 else
3157 k = char_count;
3158 break;
3159 default:
3160 pGlyphProp[i].sva.fClusterStart = 1;
3161 break;
3165 if (use_syllables)
3167 IndicSyllable *syllables = NULL;
3168 int syllable_count = 0;
3169 BOOL modern = get_GSUB_Indic2(psa, psc);
3171 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3173 for (i = 0; i < syllable_count; i++)
3175 int j;
3176 WORD g = pwLogClust[syllables[i].start];
3177 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3179 if (pwLogClust[j] != g)
3181 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3182 pwLogClust[j] = g;
3187 HeapFree(GetProcessHeap(), 0, syllables);
3190 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3193 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 )
3195 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3198 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 )
3200 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3203 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 )
3205 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3208 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 )
3210 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3213 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 )
3215 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3218 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 )
3220 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3223 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 )
3225 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3228 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 )
3230 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3233 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 )
3235 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3238 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 )
3240 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3243 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 )
3245 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3248 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)
3250 load_ot_tables(hdc, psc);
3252 if (ShapingData[psa->eScript].charGlyphPropProc)
3253 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3254 else
3255 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3258 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3260 load_ot_tables(hdc, psc);
3262 if (ShapingData[psa->eScript].contextProc)
3263 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3266 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)
3268 int i;
3269 INT dirL;
3271 if (!rpRangeProperties)
3272 return;
3274 load_ot_tables(hdc, psc);
3276 if (!psc->GSUB_Table)
3277 return;
3279 if (!psa->fLogicalOrder && psa->fRTL)
3280 dirL = -1;
3281 else
3282 dirL = 1;
3284 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3286 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3287 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3291 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3293 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3294 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3296 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3299 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3301 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3302 int i;
3304 rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3306 if (!rpRangeProperties)
3307 return;
3309 load_ot_tables(hdc, psc);
3311 if (!psc->GPOS_Table || !psc->otm)
3312 return;
3314 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3316 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3318 LoadedFeature *feature;
3320 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3321 if (!feature)
3322 continue;
3324 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3329 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3331 LoadedFeature *feature;
3332 int i;
3334 if (!ShapingData[psa->eScript].requiredFeatures)
3335 return S_OK;
3337 load_ot_tables(hdc, psc);
3339 /* we need to have at least one of the required features */
3340 i = 0;
3341 while (ShapingData[psa->eScript].requiredFeatures[i])
3343 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3344 if (feature)
3345 return S_OK;
3346 i++;
3349 return USP_E_SCRIPT_NOT_IN_FONT;
3352 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3353 SCRIPT_ANALYSIS *psa, int cMaxTags,
3354 OPENTYPE_TAG *pScriptTags, int *pcTags)
3356 HRESULT hr;
3357 OPENTYPE_TAG searching = 0x00000000;
3359 load_ot_tables(hdc, psc);
3361 if (psa && scriptInformation[psa->eScript].scriptTag)
3362 searching = scriptInformation[psa->eScript].scriptTag;
3364 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3365 if (FAILED(hr))
3366 *pcTags = 0;
3367 return hr;
3370 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3371 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3372 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3373 int *pcTags)
3375 HRESULT hr;
3376 OPENTYPE_TAG searching = 0x00000000;
3377 BOOL fellback = FALSE;
3379 load_ot_tables(hdc, psc);
3381 if (psa && psc->userLang != 0)
3382 searching = psc->userLang;
3384 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3385 if (FAILED(hr))
3387 fellback = TRUE;
3388 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3391 if (FAILED(hr) || fellback)
3392 *pcTags = 0;
3393 if (SUCCEEDED(hr) && fellback && psa)
3394 hr = E_INVALIDARG;
3395 return hr;
3398 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3399 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3400 OPENTYPE_TAG tagLangSys, int cMaxTags,
3401 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3403 HRESULT hr;
3404 BOOL filter = FALSE;
3406 load_ot_tables(hdc, psc);
3408 if (psa && scriptInformation[psa->eScript].scriptTag)
3410 FIXME("Filtering not implemented\n");
3411 filter = TRUE;
3414 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3416 if (FAILED(hr))
3417 *pcTags = 0;
3418 return hr;