d3drm: Make it possible to create frames with CreateObject().
[wine.git] / dlls / usp10 / shape.c
blob2f47f89cf4db104d7752f3553e68086f72236f48
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #define FIRST_ARABIC_CHAR 0x0600
39 #define LAST_ARABIC_CHAR 0x06ff
41 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
42 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
63 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
65 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
67 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
68 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
73 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
75 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
76 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
77 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
78 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
79 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
80 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
81 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
82 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
83 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
84 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
85 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
87 extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
88 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
89 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
91 enum joining_types {
92 jtU,
93 jtT,
94 jtR,
95 jtL,
96 jtD,
97 jtC
100 enum joined_forms {
101 Xn=0,
105 /* Syriac Alaph */
106 Afj,
107 Afn,
111 typedef struct tagVowelComponents
113 WCHAR base;
114 WCHAR parts[3];
115 } VowelComponents;
117 typedef struct tagConsonantComponents
119 WCHAR parts[3];
120 WCHAR output;
121 } ConsonantComponents;
123 typedef void (*second_reorder_function)(const WCHAR *chars, const IndicSyllable *syllable,
124 WORD *glyphs, const IndicSyllable *glyph_index, lexical_function lex);
126 typedef int (*combining_lexical_function)(WCHAR c);
128 /* the orders of joined_forms and contextual_features need to line up */
129 static const char *const contextual_features[] =
131 "isol",
132 "fina",
133 "init",
134 "medi",
135 /* Syriac Alaph */
136 "med2",
137 "fin2",
138 "fin3"
141 static OPENTYPE_FEATURE_RECORD standard_features[] =
143 { MS_MAKE_TAG('c','c','m','p'), 1},
144 { MS_MAKE_TAG('l','o','c','l'), 1},
147 static OPENTYPE_FEATURE_RECORD latin_features[] =
149 { MS_MAKE_TAG('l','o','c','l'), 1},
150 { MS_MAKE_TAG('c','c','m','p'), 1},
151 { MS_MAKE_TAG('l','i','g','a'), 1},
152 { MS_MAKE_TAG('c','l','i','g'), 1},
155 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
157 { MS_MAKE_TAG('k','e','r','n'), 1},
158 { MS_MAKE_TAG('m','a','r','k'), 1},
159 { MS_MAKE_TAG('m','k','m','k'), 1},
162 static OPENTYPE_FEATURE_RECORD arabic_features[] =
164 { MS_MAKE_TAG('r','l','i','g'), 1},
165 { MS_MAKE_TAG('c','a','l','t'), 1},
166 { MS_MAKE_TAG('l','i','g','a'), 1},
167 { MS_MAKE_TAG('d','l','i','g'), 1},
168 { MS_MAKE_TAG('c','s','w','h'), 1},
169 { MS_MAKE_TAG('m','s','e','t'), 1},
172 static const char *const required_arabic_features[] =
174 "fina",
175 "init",
176 "medi",
177 "rlig",
178 NULL
181 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
183 { MS_MAKE_TAG('c','u','r','s'), 1},
184 { MS_MAKE_TAG('k','e','r','n'), 1},
185 { MS_MAKE_TAG('m','a','r','k'), 1},
186 { MS_MAKE_TAG('m','k','m','k'), 1},
189 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
191 { MS_MAKE_TAG('c','c','m','p'), 1},
192 { MS_MAKE_TAG('d','l','i','g'), 0},
195 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
197 { MS_MAKE_TAG('k','e','r','n'), 1},
198 { MS_MAKE_TAG('m','a','r','k'), 1},
201 static OPENTYPE_FEATURE_RECORD syriac_features[] =
203 { MS_MAKE_TAG('r','l','i','g'), 1},
204 { MS_MAKE_TAG('c','a','l','t'), 1},
205 { MS_MAKE_TAG('l','i','g','a'), 1},
206 { MS_MAKE_TAG('d','l','i','g'), 1},
209 static const char *const required_syriac_features[] =
211 "fina",
212 "fin2",
213 "fin3",
214 "init",
215 "medi",
216 "med2",
217 "rlig",
218 NULL
221 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
223 { MS_MAKE_TAG('k','e','r','n'), 1},
224 { MS_MAKE_TAG('m','a','r','k'), 1},
225 { MS_MAKE_TAG('m','k','m','k'), 1},
228 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
230 /* Presentation forms */
231 { MS_MAKE_TAG('b','l','w','s'), 1},
232 { MS_MAKE_TAG('a','b','v','s'), 1},
233 { MS_MAKE_TAG('p','s','t','s'), 1},
236 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
238 { MS_MAKE_TAG('a','b','v','s'), 1},
239 { MS_MAKE_TAG('b','l','w','s'), 1},
242 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
244 { MS_MAKE_TAG('a','b','v','m'), 1},
245 { MS_MAKE_TAG('b','l','w','m'), 1},
248 static OPENTYPE_FEATURE_RECORD phags_features[] =
250 { MS_MAKE_TAG('a','b','v','s'), 1},
251 { MS_MAKE_TAG('b','l','w','s'), 1},
252 { MS_MAKE_TAG('c','a','l','t'), 1},
255 static OPENTYPE_FEATURE_RECORD thai_features[] =
257 { MS_MAKE_TAG('c','c','m','p'), 1},
260 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
262 { MS_MAKE_TAG('k','e','r','n'), 1},
263 { MS_MAKE_TAG('m','a','r','k'), 1},
264 { MS_MAKE_TAG('m','k','m','k'), 1},
267 static const char *const required_lao_features[] =
269 "ccmp",
270 NULL
273 static const char *const required_devanagari_features[] =
275 "nukt",
276 "akhn",
277 "rphf",
278 "blwf",
279 "half",
280 "vatu",
281 "pres",
282 "abvs",
283 "blws",
284 "psts",
285 "haln",
286 NULL
289 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
291 { MS_MAKE_TAG('p','r','e','s'), 1},
292 { MS_MAKE_TAG('a','b','v','s'), 1},
293 { MS_MAKE_TAG('b','l','w','s'), 1},
294 { MS_MAKE_TAG('p','s','t','s'), 1},
295 { MS_MAKE_TAG('h','a','l','n'), 1},
296 { MS_MAKE_TAG('c','a','l','t'), 1},
299 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
301 { MS_MAKE_TAG('k','e','r','n'), 1},
302 { MS_MAKE_TAG('d','i','s','t'), 1},
303 { MS_MAKE_TAG('a','b','v','m'), 1},
304 { MS_MAKE_TAG('b','l','w','m'), 1},
307 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
309 { MS_MAKE_TAG('l','i','g','a'), 1},
310 { MS_MAKE_TAG('c','l','i','g'), 1},
313 static const char *const required_bengali_features[] =
315 "nukt",
316 "akhn",
317 "rphf",
318 "blwf",
319 "half",
320 "vatu",
321 "pstf",
322 "init",
323 "abvs",
324 "blws",
325 "psts",
326 "haln",
327 NULL
330 static const char *const required_gurmukhi_features[] =
332 "nukt",
333 "akhn",
334 "rphf",
335 "blwf",
336 "half",
337 "pstf",
338 "vatu",
339 "cjct",
340 "pres",
341 "abvs",
342 "blws",
343 "psts",
344 "haln",
345 "calt",
346 NULL
349 static const char *const required_oriya_features[] =
351 "nukt",
352 "akhn",
353 "rphf",
354 "blwf",
355 "pstf",
356 "cjct",
357 "pres",
358 "abvs",
359 "blws",
360 "psts",
361 "haln",
362 "calt",
363 NULL
366 static const char *const required_tamil_features[] =
368 "nukt",
369 "akhn",
370 "rphf",
371 "pref",
372 "half",
373 "pres",
374 "abvs",
375 "blws",
376 "psts",
377 "haln",
378 "calt",
379 NULL
382 static const char *const required_telugu_features[] =
384 "nukt",
385 "akhn",
386 "rphf",
387 "pref",
388 "half",
389 "pstf",
390 "cjct",
391 "pres",
392 "abvs",
393 "blws",
394 "psts",
395 "haln",
396 "calt",
397 NULL
400 static OPENTYPE_FEATURE_RECORD khmer_features[] =
402 { MS_MAKE_TAG('p','r','e','s'), 1},
403 { MS_MAKE_TAG('b','l','w','s'), 1},
404 { MS_MAKE_TAG('a','b','v','s'), 1},
405 { MS_MAKE_TAG('p','s','t','s'), 1},
406 { MS_MAKE_TAG('c','l','i','g'), 1},
409 static const char *const required_khmer_features[] =
411 "pref",
412 "blwf",
413 "abvf",
414 "pstf",
415 "pres",
416 "blws",
417 "abvs",
418 "psts",
419 "clig",
420 NULL
423 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
425 { MS_MAKE_TAG('d','i','s','t'), 1},
426 { MS_MAKE_TAG('b','l','w','m'), 1},
427 { MS_MAKE_TAG('a','b','v','m'), 1},
428 { MS_MAKE_TAG('m','k','m','k'), 1},
431 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
433 { MS_MAKE_TAG('c','c','m','p'), 1},
434 { MS_MAKE_TAG('l','o','c','l'), 1},
435 { MS_MAKE_TAG('c','a','l','t'), 1},
436 { MS_MAKE_TAG('l','i','g','a'), 1},
439 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
441 { MS_MAKE_TAG('c','c','m','p'), 1},
442 { MS_MAKE_TAG('l','o','c','l'), 1},
443 { MS_MAKE_TAG('c','a','l','t'), 1},
444 { MS_MAKE_TAG('r','l','i','g'), 1},
447 typedef struct ScriptShapeDataTag {
448 TEXTRANGE_PROPERTIES defaultTextRange;
449 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
450 const char *const *requiredFeatures;
451 OPENTYPE_TAG newOtTag;
452 ContextualShapingProc contextProc;
453 ShapeCharGlyphPropProc charGlyphPropProc;
454 } ScriptShapeData;
456 /* in order of scripts */
457 static const ScriptShapeData ShapingData[] =
459 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
460 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
461 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
462 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
463 {{ standard_features, 2}, {NULL, 0}, NULL, 0, ContextualShape_Control, ShapeCharGlyphProp_Control},
464 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
465 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
466 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
467 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
468 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
469 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
470 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
471 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
472 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
473 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
474 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
475 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
476 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
477 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
478 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
479 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
480 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
481 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
482 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
483 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
497 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
498 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
499 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
500 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
501 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
502 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
503 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
504 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
505 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
506 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
511 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
512 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
513 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
516 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
522 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
523 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
524 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
526 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
527 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
528 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
529 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
530 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
531 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
532 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
533 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
534 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
535 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
536 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
537 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
538 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
539 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
540 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
543 extern scriptData scriptInformation[];
545 static int GSUB_apply_feature_all_lookups(const void *header, LoadedFeature *feature,
546 WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count)
548 int i;
549 int out_index = GSUB_E_NOGLYPH;
551 TRACE("%i lookups\n", feature->lookup_count);
552 for (i = 0; i < feature->lookup_count; i++)
554 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
555 if (out_index != GSUB_E_NOGLYPH)
556 break;
558 if (out_index == GSUB_E_NOGLYPH)
559 TRACE("lookups found no glyphs\n");
560 else
562 int out2;
563 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
564 if (out2!=GSUB_E_NOGLYPH)
565 out_index = out2;
567 return out_index;
570 static OPENTYPE_TAG get_opentype_script(HDC hdc, const SCRIPT_ANALYSIS *psa,
571 const ScriptCache *script_cache, BOOL try_new)
573 UINT charset;
575 if (script_cache->userScript)
577 if (try_new && ShapingData[psa->eScript].newOtTag
578 && script_cache->userScript == scriptInformation[psa->eScript].scriptTag)
579 return ShapingData[psa->eScript].newOtTag;
581 return script_cache->userScript;
584 if (try_new && ShapingData[psa->eScript].newOtTag)
585 return ShapingData[psa->eScript].newOtTag;
587 if (scriptInformation[psa->eScript].scriptTag)
588 return scriptInformation[psa->eScript].scriptTag;
591 * fall back to the font charset
593 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
594 switch (charset)
596 case ANSI_CHARSET:
597 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
598 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
599 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
600 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
601 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
602 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
603 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
604 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
605 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
606 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
607 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
608 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
609 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
610 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
611 default: return MS_MAKE_TAG('l','a','t','n');
615 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
617 LoadedFeature *feature = NULL;
619 if (psc->GSUB_Table || psc->GPOS_Table)
621 int attempt = 2;
622 OPENTYPE_TAG tags;
623 OPENTYPE_TAG language;
624 OPENTYPE_TAG script = 0x00000000;
625 int cTags;
629 script = get_opentype_script(hdc,psa,psc,(attempt==2));
630 if (psc->userLang != 0)
631 language = psc->userLang;
632 else
633 language = MS_MAKE_TAG('d','f','l','t');
634 attempt--;
636 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
638 } while(attempt && !feature);
640 /* try in the default (latin) table */
641 if (!feature && !script)
642 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);
645 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
646 return feature;
649 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)
651 LoadedFeature *feature;
653 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
654 if (!feature)
655 return GSUB_E_NOFEATURE;
657 TRACE("applying feature %s\n",feat);
658 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
661 static VOID *load_gsub_table(HDC hdc)
663 VOID* GSUB_Table = NULL;
664 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
665 if (length != GDI_ERROR)
667 GSUB_Table = heap_alloc(length);
668 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
669 TRACE("Loaded GSUB table of %i bytes\n",length);
671 return GSUB_Table;
674 static VOID *load_gpos_table(HDC hdc)
676 VOID* GPOS_Table = NULL;
677 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
678 if (length != GDI_ERROR)
680 GPOS_Table = heap_alloc(length);
681 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
682 TRACE("Loaded GPOS table of %i bytes\n",length);
684 return GPOS_Table;
687 static VOID *load_gdef_table(HDC hdc)
689 VOID* GDEF_Table = NULL;
690 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
691 if (length != GDI_ERROR)
693 GDEF_Table = heap_alloc(length);
694 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
695 TRACE("Loaded GDEF table of %i bytes\n",length);
697 return GDEF_Table;
700 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
702 if (!psc->GSUB_Table)
703 psc->GSUB_Table = load_gsub_table(hdc);
704 if (!psc->GPOS_Table)
705 psc->GPOS_Table = load_gpos_table(hdc);
706 if (!psc->GDEF_Table)
707 psc->GDEF_Table = load_gdef_table(hdc);
710 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)
712 WORD *glyphs;
713 INT glyph_count = count;
714 INT rc;
716 glyphs = heap_alloc(2 * count * sizeof(*glyphs));
717 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
718 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
719 if (rc > GSUB_E_NOGLYPH)
720 rc = count - glyph_count;
721 else
722 rc = 0;
724 heap_free(glyphs);
725 return rc;
728 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
730 int i;
732 for (i = 0; i < cGlyphs; i++)
734 if (!pGlyphProp[i].sva.fClusterStart)
736 int j;
737 for (j = 0; j < cChars; j++)
739 if (pwLogClust[j] == i)
741 int k = j;
742 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
743 k-=1;
744 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
745 pwLogClust[j] = pwLogClust[k];
752 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
754 if (changeCount == 0)
755 return;
756 else
758 int cluster_dir = pwLogClust[0] < pwLogClust[chars-1] ? 1 : -1;
759 int i;
760 int target_glyph = nextIndex - write_dir;
761 int target_index = -1;
762 int replacing_glyph = -1;
763 int changed = 0;
765 if (changeCount > 0)
767 if (write_dir > 0)
768 target_glyph = nextIndex - changeCount;
769 else
770 target_glyph = nextIndex + (changeCount + 1);
773 target_index = USP10_FindGlyphInLogClust(pwLogClust, chars, target_glyph);
774 if (target_index == -1)
776 ERR("Unable to find target glyph\n");
777 return;
780 if (changeCount < 0)
782 /* merge glyphs */
783 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
785 if (pwLogClust[i] == target_glyph)
786 continue;
787 if(pwLogClust[i] == replacing_glyph)
788 pwLogClust[i] = target_glyph;
789 else
791 changed--;
792 if (changed >= changeCount)
794 replacing_glyph = pwLogClust[i];
795 pwLogClust[i] = target_glyph;
797 else
798 break;
802 /* renumber trailing indexes */
803 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
805 if (pwLogClust[i] != target_glyph)
806 pwLogClust[i] += changeCount;
809 else
811 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
812 pwLogClust[i] += changeCount;
817 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 )
819 if (psc->GSUB_Table)
821 LoadedFeature *feature;
822 int lookup_index;
824 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
825 if (!feature)
826 return GSUB_E_NOFEATURE;
828 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
829 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
831 int i;
833 if (write_dir > 0)
834 i = 0;
835 else
836 i = *pcGlyphs-1;
837 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
838 while(i < *pcGlyphs && i >= 0)
840 INT nextIndex;
841 INT prevCount = *pcGlyphs;
843 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
844 if (*pcGlyphs != prevCount)
846 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
847 i = nextIndex;
849 else
850 i+=write_dir;
853 return *pcGlyphs;
855 return GSUB_E_NOFEATURE;
858 static void GPOS_apply_feature(const ScriptCache *psc, const OUTLINETEXTMETRICW *otm,
859 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance,
860 const LoadedFeature *feature, const WORD *glyphs, int glyph_count, GOFFSET *goffset)
862 int dir = analysis->fLogicalOrder && analysis->fRTL ? -1 : 1;
863 unsigned int start_idx, i, j;
865 TRACE("%i lookups\n", feature->lookup_count);
867 start_idx = dir < 0 ? glyph_count - 1 : 0;
868 for (i = 0; i < feature->lookup_count; i++)
870 for (j = 0; j < glyph_count; )
871 j += OpenType_apply_GPOS_lookup(psc, otm, logfont, analysis, advance,
872 feature->lookups[i], glyphs, start_idx + dir * j, glyph_count, goffset);
876 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
878 OPENTYPE_TAG tag;
879 HRESULT hr;
880 int count = 0;
882 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
884 return(SUCCEEDED(hr));
887 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
889 int i;
890 for (i = *pcGlyphs; i>=index; i--)
891 pwGlyphs[i+1] = pwGlyphs[i];
892 pwGlyphs[index] = glyph;
893 *pcGlyphs = *pcGlyphs+1;
894 if (write_dir < 0)
895 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
896 else
897 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
900 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)
902 CHAR *context_type;
903 int i,g;
904 WCHAR invalid = 0x25cc;
905 WORD invalid_glyph;
907 context_type = heap_alloc(cChars);
909 /* Mark invalid combinations */
910 for (i = 0; i < cChars; i++)
911 context_type[i] = lex(pwcChars[i]);
913 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
914 for (i = 1, g=1; i < cChars - 1; i++, g++)
916 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
918 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
919 g++;
923 heap_free(context_type);
926 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
928 int i;
929 for (i=0; i < cChars; i++)
931 switch (pwcChars[i])
933 case 0x000A:
934 case 0x000D:
935 pwOutGlyphs[i] = psc->sfp.wgBlank;
936 break;
937 default:
938 if (pwcChars[i] < 0x1C)
939 pwOutGlyphs[i] = psc->sfp.wgDefault;
940 else
941 pwOutGlyphs[i] = psc->sfp.wgBlank;
946 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
948 if (i + delta < 0)
949 return 0;
950 if ( i+ delta >= cchLen)
951 return 0;
953 i += delta;
955 return chars[i];
958 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
960 if (i + delta < 0)
962 if (psa->fLinkBefore)
963 return jtR;
964 else
965 return jtU;
967 if ( i+ delta >= cchLen)
969 if (psa->fLinkAfter)
970 return jtL;
971 else
972 return jtU;
975 i += delta;
977 if (context_type[i] == jtT)
978 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
979 else
980 return context_type[i];
983 static inline BOOL right_join_causing(CHAR joining_type)
985 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
988 static inline BOOL left_join_causing(CHAR joining_type)
990 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
993 static inline BOOL word_break_causing(WCHAR chr)
995 /* we are working within a string of characters already guareented to
996 be within one script, Syriac, so we do not worry about any character
997 other than the space character outside of that range */
998 return (chr == 0 || chr == 0x20 );
1001 static int combining_lexical_Arabic(WCHAR c)
1003 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1005 switch(c)
1007 case 0x064B:
1008 case 0x064C:
1009 case 0x064E:
1010 case 0x064F:
1011 case 0x0652:
1012 case 0x0657:
1013 case 0x0658:
1014 case 0x06E1: return Arab_DIAC1;
1015 case 0x064D:
1016 case 0x0650:
1017 case 0x0656: return Arab_DIAC2;
1018 case 0x0651: return Arab_DIAC3;
1019 case 0x0610:
1020 case 0x0611:
1021 case 0x0612:
1022 case 0x0613:
1023 case 0x0614:
1024 case 0x0659:
1025 case 0x06D6:
1026 case 0x06DC:
1027 case 0x06DF:
1028 case 0x06E0:
1029 case 0x06E2:
1030 case 0x06E4:
1031 case 0x06E7:
1032 case 0x06E8:
1033 case 0x06EB:
1034 case 0x06EC: return Arab_DIAC4;
1035 case 0x06E3:
1036 case 0x06EA:
1037 case 0x06ED: return Arab_DIAC5;
1038 case 0x0670: return Arab_DIAC6;
1039 case 0x0653: return Arab_DIAC7;
1040 case 0x0655:
1041 case 0x0654: return Arab_DIAC8;
1042 default: return Arab_Norm;
1047 * ContextualShape_Arabic
1049 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1051 CHAR *context_type;
1052 INT *context_shape;
1053 INT dirR, dirL;
1054 int i;
1055 int char_index;
1056 int glyph_index;
1058 if (*pcGlyphs != cChars)
1060 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1061 return;
1064 if (psa->fLogicalOrder && psa->fRTL)
1066 dirR = -1;
1067 dirL = 1;
1069 else
1071 dirR = 1;
1072 dirL = -1;
1075 load_ot_tables(hdc, psc);
1077 context_type = heap_alloc(cChars);
1078 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1080 for (i = 0; i < cChars; i++)
1081 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1083 for (i = 0; i < cChars; i++)
1085 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1086 context_shape[i] = Xr;
1087 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1088 context_shape[i] = Xl;
1089 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)))
1090 context_shape[i] = Xm;
1091 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1092 context_shape[i] = Xr;
1093 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1094 context_shape[i] = Xl;
1095 else
1096 context_shape[i] = Xn;
1099 /* Contextual Shaping */
1100 if (dirL > 0)
1101 char_index = glyph_index = 0;
1102 else
1103 char_index = glyph_index = cChars-1;
1105 while(char_index < cChars && char_index >= 0)
1107 BOOL shaped = FALSE;
1109 if (psc->GSUB_Table)
1111 INT nextIndex, offset = 0;
1112 INT prevCount = *pcGlyphs;
1114 /* Apply CCMP first */
1115 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1117 if (prevCount != *pcGlyphs)
1119 offset = *pcGlyphs - prevCount;
1120 if (dirL < 0)
1121 glyph_index -= offset * dirL;
1124 /* Apply the contextual feature */
1125 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1127 if (nextIndex > GSUB_E_NOGLYPH)
1129 UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1130 char_index += dirL;
1131 if (!offset)
1132 glyph_index = nextIndex;
1133 else
1135 offset = *pcGlyphs - prevCount;
1136 glyph_index += dirL * (offset + 1);
1138 shaped = TRUE;
1140 else if (nextIndex == GSUB_E_NOGLYPH)
1142 char_index += dirL;
1143 glyph_index += dirL;
1144 shaped = TRUE;
1148 if (!shaped)
1150 if (context_shape[char_index] == Xn)
1152 WORD newGlyph = pwOutGlyphs[glyph_index];
1153 if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
1155 /* fall back to presentation form B */
1156 WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
1157 if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1158 pwOutGlyphs[glyph_index] = newGlyph;
1161 char_index += dirL;
1162 glyph_index += dirL;
1166 heap_free(context_shape);
1167 heap_free(context_type);
1169 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1172 static int combining_lexical_Hebrew(WCHAR c)
1174 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};
1176 switch(c)
1178 case 0x05B0:
1179 case 0x05B1:
1180 case 0x05B2:
1181 case 0x05B3:
1182 case 0x05B4:
1183 case 0x05B5:
1184 case 0x05B6:
1185 case 0x05BB: return Hebr_DIAC;
1186 case 0x0599:
1187 case 0x05A1:
1188 case 0x05A9:
1189 case 0x05AE: return Hebr_CANT1;
1190 case 0x0597:
1191 case 0x05A8:
1192 case 0x05AC: return Hebr_CANT2;
1193 case 0x0592:
1194 case 0x0593:
1195 case 0x0594:
1196 case 0x0595:
1197 case 0x05A7:
1198 case 0x05AB: return Hebr_CANT3;
1199 case 0x0598:
1200 case 0x059C:
1201 case 0x059E:
1202 case 0x059F: return Hebr_CANT4;
1203 case 0x059D:
1204 case 0x05A0: return Hebr_CANT5;
1205 case 0x059B:
1206 case 0x05A5: return Hebr_CANT6;
1207 case 0x0591:
1208 case 0x05A3:
1209 case 0x05A6: return Hebr_CANT7;
1210 case 0x0596:
1211 case 0x05A4:
1212 case 0x05AA: return Hebr_CANT8;
1213 case 0x059A:
1214 case 0x05AD: return Hebr_CANT9;
1215 case 0x05AF: return Hebr_CANT10;
1216 case 0x05BC: return Hebr_DAGESH;
1217 case 0x05C4: return Hebr_DOTABV;
1218 case 0x05B9: return Hebr_HOLAM;
1219 case 0x05BD: return Hebr_METEG;
1220 case 0x05B7: return Hebr_PATAH;
1221 case 0x05B8: return Hebr_QAMATS;
1222 case 0x05BF: return Hebr_RAFE;
1223 case 0x05C1:
1224 case 0x05C2: return Hebr_SHINSIN;
1225 default: return Hebr_Norm;
1229 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1231 INT dirL;
1233 if (*pcGlyphs != cChars)
1235 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1236 return;
1239 if (!psa->fLogicalOrder && psa->fRTL)
1240 dirL = -1;
1241 else
1242 dirL = 1;
1244 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1248 * ContextualShape_Syriac
1251 static int combining_lexical_Syriac(WCHAR c)
1253 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};
1255 switch(c)
1257 case 0x730:
1258 case 0x733:
1259 case 0x736:
1260 case 0x73A:
1261 case 0x73D: return Syriac_DIAC1;
1262 case 0x731:
1263 case 0x734:
1264 case 0x737:
1265 case 0x73B:
1266 case 0x73E: return Syriac_DIAC2;
1267 case 0x740:
1268 case 0x749:
1269 case 0x74A: return Syriac_DIAC3;
1270 case 0x732:
1271 case 0x735:
1272 case 0x73F: return Syriac_DIAC4;
1273 case 0x738:
1274 case 0x739:
1275 case 0x73C: return Syriac_DIAC5;
1276 case 0x741:
1277 case 0x30A: return Syriac_DIAC6;
1278 case 0x742:
1279 case 0x325: return Syriac_DIAC7;
1280 case 0x747:
1281 case 0x303: return Syriac_DIAC8;
1282 case 0x748:
1283 case 0x32D:
1284 case 0x32E:
1285 case 0x330:
1286 case 0x331: return Syriac_DIAC9;
1287 case 0x308: return Syriac_DIAC10;
1288 case 0x304: return Syriac_DIAC11;
1289 case 0x307: return Syriac_DIAC12;
1290 case 0x323: return Syriac_DIAC13;
1291 case 0x743: return Syriac_DIAC14;
1292 case 0x744: return Syriac_DIAC15;
1293 case 0x745: return Syriac_DIAC16;
1294 case 0x746: return Syriac_DIAC17;
1295 default: return Syriac_Norm;
1299 #define ALAPH 0x710
1300 #define DALATH 0x715
1301 #define RISH 0x72A
1303 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1305 CHAR *context_type;
1306 INT *context_shape;
1307 INT dirR, dirL;
1308 int i;
1309 int char_index;
1310 int glyph_index;
1312 if (*pcGlyphs != cChars)
1314 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1315 return;
1318 if (!psa->fLogicalOrder && psa->fRTL)
1320 dirR = 1;
1321 dirL = -1;
1323 else
1325 dirR = -1;
1326 dirL = 1;
1329 load_ot_tables(hdc, psc);
1331 if (!psc->GSUB_Table)
1332 return;
1334 context_type = heap_alloc(cChars);
1335 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1337 for (i = 0; i < cChars; i++)
1338 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1340 for (i = 0; i < cChars; i++)
1342 if (pwcChars[i] == ALAPH)
1344 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1346 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1347 context_shape[i] = Afj;
1348 else if ( rchar != DALATH && rchar != RISH &&
1349 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1350 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1351 context_shape[i] = Afn;
1352 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1353 context_shape[i] = Afx;
1354 else
1355 context_shape[i] = Xn;
1357 else if (context_type[i] == jtR &&
1358 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1359 context_shape[i] = Xr;
1360 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1361 context_shape[i] = Xl;
1362 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)))
1363 context_shape[i] = Xm;
1364 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1365 context_shape[i] = Xr;
1366 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1367 context_shape[i] = Xl;
1368 else
1369 context_shape[i] = Xn;
1372 /* Contextual Shaping */
1373 if (dirL > 0)
1374 char_index = glyph_index = 0;
1375 else
1376 char_index = glyph_index = cChars-1;
1378 while(char_index < cChars && char_index >= 0)
1380 INT nextIndex, offset = 0;
1381 INT prevCount = *pcGlyphs;
1383 /* Apply CCMP first */
1384 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1386 if (prevCount != *pcGlyphs)
1388 offset = *pcGlyphs - prevCount;
1389 if (dirL < 0)
1390 glyph_index -= offset * dirL;
1393 /* Apply the contextual feature */
1394 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1395 if (nextIndex > GSUB_E_NOGLYPH)
1397 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1398 char_index += dirL;
1399 if (!offset)
1400 glyph_index = nextIndex;
1401 else
1403 offset = *pcGlyphs - prevCount;
1404 glyph_index += dirL * (offset + 1);
1407 else
1409 char_index += dirL;
1410 glyph_index += dirL;
1414 heap_free(context_shape);
1415 heap_free(context_type);
1417 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1420 static int combining_lexical_Thaana(WCHAR c)
1422 enum {Thaana_Norm=0, Thaana_FILI};
1424 switch(c)
1426 case 0x7A6:
1427 case 0x7A7:
1428 case 0x7A8:
1429 case 0x7A9:
1430 case 0x7AA:
1431 case 0x7AB:
1432 case 0x7AC:
1433 case 0x7AD:
1434 case 0x7AE:
1435 case 0x7AF: return Thaana_FILI;
1436 default: return Thaana_Norm;
1440 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1442 INT dirL;
1444 if (*pcGlyphs != cChars)
1446 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1447 return;
1450 if (!psa->fLogicalOrder && psa->fRTL)
1451 dirL = -1;
1452 else
1453 dirL = 1;
1455 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1459 * ContextualShape_Phags_pa
1462 #define phags_pa_CANDRABINDU 0xA873
1463 #define phags_pa_START 0xA840
1464 #define phags_pa_END 0xA87F
1466 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1468 INT *context_shape;
1469 INT dirR, dirL;
1470 int i;
1471 int char_index;
1472 int glyph_index;
1474 if (*pcGlyphs != cChars)
1476 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1477 return;
1480 if (!psa->fLogicalOrder && psa->fRTL)
1482 dirR = 1;
1483 dirL = -1;
1485 else
1487 dirR = -1;
1488 dirL = 1;
1491 load_ot_tables(hdc, psc);
1493 if (!psc->GSUB_Table)
1494 return;
1496 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1498 for (i = 0; i < cChars; i++)
1500 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1502 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1503 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1504 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1505 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1507 if (jrchar && jlchar)
1508 context_shape[i] = Xm;
1509 else if (jrchar)
1510 context_shape[i] = Xr;
1511 else if (jlchar)
1512 context_shape[i] = Xl;
1513 else
1514 context_shape[i] = Xn;
1516 else
1517 context_shape[i] = -1;
1520 /* Contextual Shaping */
1521 if (dirL > 0)
1522 char_index = glyph_index = 0;
1523 else
1524 char_index = glyph_index = cChars-1;
1526 while(char_index < cChars && char_index >= 0)
1528 if (context_shape[char_index] >= 0)
1530 INT nextIndex;
1531 INT prevCount = *pcGlyphs;
1532 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1534 if (nextIndex > GSUB_E_NOGLYPH)
1536 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1537 glyph_index = nextIndex;
1538 char_index += dirL;
1540 else
1542 char_index += dirL;
1543 glyph_index += dirL;
1546 else
1548 char_index += dirL;
1549 glyph_index += dirL;
1553 heap_free(context_shape);
1556 static int combining_lexical_Thai(WCHAR c)
1558 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1560 switch(c)
1562 case 0xE31:
1563 case 0xE34:
1564 case 0xE35:
1565 case 0xE36:
1566 case 0xE37: return Thai_ABOVE1;
1567 case 0xE47:
1568 case 0xE4D: return Thai_ABOVE2;
1569 case 0xE48:
1570 case 0xE49:
1571 case 0xE4A:
1572 case 0xE4B: return Thai_ABOVE3;
1573 case 0xE4C:
1574 case 0xE4E: return Thai_ABOVE4;
1575 case 0xE38:
1576 case 0xE39: return Thai_BELOW1;
1577 case 0xE3A: return Thai_BELOW2;
1578 case 0xE33: return Thai_AM;
1579 default: return Thai_Norm;
1583 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1585 INT dirL;
1587 if (*pcGlyphs != cChars)
1589 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1590 return;
1593 if (!psa->fLogicalOrder && psa->fRTL)
1594 dirL = -1;
1595 else
1596 dirL = 1;
1598 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1601 static int combining_lexical_Lao(WCHAR c)
1603 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1605 switch(c)
1607 case 0xEB1:
1608 case 0xEB4:
1609 case 0xEB5:
1610 case 0xEB6:
1611 case 0xEB7:
1612 case 0xEBB:
1613 case 0xECD: return Lao_ABOVE1;
1614 case 0xEC8:
1615 case 0xEC9:
1616 case 0xECA:
1617 case 0xECB:
1618 case 0xECC: return Lao_ABOVE2;
1619 case 0xEBC: return Lao_BELOW1;
1620 case 0xEB8:
1621 case 0xEB9: return Lao_BELOW2;
1622 case 0xEB3: return Lao_AM;
1623 default: return Lao_Norm;
1627 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1629 INT dirL;
1631 if (*pcGlyphs != cChars)
1633 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1634 return;
1637 if (!psa->fLogicalOrder && psa->fRTL)
1638 dirL = -1;
1639 else
1640 dirL = 1;
1642 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1645 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1647 int i;
1649 /* Replace */
1650 pwOutChars[cWalk] = replacements[0];
1651 cWalk=cWalk+1;
1653 /* Insert */
1654 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1656 int j;
1657 for (j = *pcChars; j > cWalk; j--)
1658 pwOutChars[j] = pwOutChars[j-1];
1659 *pcChars= *pcChars+1;
1660 pwOutChars[cWalk] = replacements[i];
1661 cWalk = cWalk+1;
1665 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1667 int i;
1668 int cWalk;
1670 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1672 for (i = 0; vowels[i].base != 0x0; i++)
1674 if (pwOutChars[cWalk] == vowels[i].base)
1676 int o = 0;
1677 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1678 if (vowels[i].parts[1]) { cWalk++; o++; }
1679 if (vowels[i].parts[2]) { cWalk++; o++; }
1680 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1681 break;
1687 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1689 int i;
1690 int offset = 0;
1691 int cWalk;
1693 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1695 for (i = 0; consonants[i].output!= 0x0; i++)
1697 int j;
1698 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1699 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1700 break;
1702 if (consonants[i].parts[j]==0x0) /* matched all */
1704 int k;
1705 j--;
1706 pwOutChars[cWalk] = consonants[i].output;
1707 for(k = cWalk+1; k < *pcChars - j; k++)
1708 pwOutChars[k] = pwOutChars[k+j];
1709 *pcChars = *pcChars - j;
1710 for (k = j ; k > 0; k--)
1711 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1712 offset += j;
1713 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1714 pwLogClust[k]--;
1715 break;
1718 cWalk++;
1722 static void Reorder_Ra_follows_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1724 if (s->ralf >= 0)
1726 int j;
1727 WORD Ra = pwChar[s->start];
1728 WORD H = pwChar[s->start+1];
1730 TRACE("Doing reorder of Ra to %i\n",s->base);
1731 for (j = s->start; j < s->base-1; j++)
1732 pwChar[j] = pwChar[j+2];
1733 pwChar[s->base-1] = Ra;
1734 pwChar[s->base] = H;
1736 s->ralf = s->base-1;
1737 s->base -= 2;
1741 static void Reorder_Ra_follows_matra(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1743 if (s->ralf >= 0)
1745 int j,loc;
1746 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1747 WORD Ra = pwChar[s->start];
1748 WORD H = pwChar[s->start+1];
1749 for (loc = s->end; loc > stop; loc--)
1750 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1751 break;
1753 TRACE("Doing reorder of Ra to %i\n",loc);
1754 for (j = s->start; j < loc-1; j++)
1755 pwChar[j] = pwChar[j+2];
1756 pwChar[loc-1] = Ra;
1757 pwChar[loc] = H;
1759 s->ralf = loc-1;
1760 s->base -= 2;
1761 if (s->blwf >= 0) s->blwf -= 2;
1762 if (s->pref >= 0) s->pref -= 2;
1766 static void Reorder_Ra_follows_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1768 if (s->ralf >= 0)
1770 int j;
1771 WORD Ra = pwChar[s->start];
1772 WORD H = pwChar[s->start+1];
1774 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1775 for (j = s->start; j < s->end-1; j++)
1776 pwChar[j] = pwChar[j+2];
1777 pwChar[s->end-1] = Ra;
1778 pwChar[s->end] = H;
1780 s->ralf = s->end-1;
1781 s->base -= 2;
1782 if (s->blwf >= 0) s->blwf -= 2;
1783 if (s->pref >= 0) s->pref -= 2;
1787 static void Reorder_Matra_precede_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1789 int i;
1791 /* reorder Matras */
1792 if (s->end > s->base)
1794 for (i = 1; i <= s->end-s->base; i++)
1796 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1798 int j;
1799 WCHAR c = pwChar[s->base+i];
1800 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1801 for (j = s->base+i; j > s->base; j--)
1802 pwChar[j] = pwChar[j-1];
1803 pwChar[s->base] = c;
1805 if (s->ralf >= s->base) s->ralf++;
1806 if (s->blwf >= s->base) s->blwf++;
1807 if (s->pref >= s->base) s->pref++;
1808 s->base ++;
1814 static void Reorder_Matra_precede_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1816 int i;
1818 /* reorder Matras */
1819 if (s->end > s->base)
1821 for (i = 1; i <= s->end-s->base; i++)
1823 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1825 int j;
1826 WCHAR c = pwChar[s->base+i];
1827 TRACE("Doing reorder of %x to %i\n",c,s->start);
1828 for (j = s->base+i; j > s->start; j--)
1829 pwChar[j] = pwChar[j-1];
1830 pwChar[s->start] = c;
1832 if (s->ralf >= 0) s->ralf++;
1833 if (s->blwf >= 0) s->blwf++;
1834 if (s->pref >= 0) s->pref++;
1835 s->base ++;
1841 static void SecondReorder_Blwf_follows_matra(const WCHAR *chars, const IndicSyllable *s,
1842 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1844 if (s->blwf >= 0 && g->blwf > g->base)
1846 int j,loc;
1847 int g_offset;
1848 for (loc = s->end; loc > s->blwf; loc--)
1849 if (lexical(chars[loc]) == lex_Matra_below || lexical(chars[loc]) == lex_Matra_above
1850 || lexical(chars[loc]) == lex_Matra_post)
1851 break;
1853 g_offset = (loc - s->blwf) - 1;
1855 if (loc != s->blwf)
1857 WORD blwf = glyphs[g->blwf];
1858 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1859 /* do not care about the pwChar array anymore, just the glyphs */
1860 for (j = 0; j < g_offset; j++)
1861 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1862 glyphs[g->blwf + g_offset] = blwf;
1867 static void SecondReorder_Matra_precede_base(const WCHAR *chars, const IndicSyllable *s,
1868 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1870 int i;
1872 /* reorder previously moved Matras to correct position*/
1873 for (i = s->start; i < s->base; i++)
1875 if (lexical(chars[i]) == lex_Matra_pre)
1877 int j;
1878 int g_start = g->start + i - s->start;
1879 if (g_start < g->base -1 )
1881 WCHAR og = glyphs[g_start];
1882 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1883 for (j = g_start; j < g->base-1; j++)
1884 glyphs[j] = glyphs[j+1];
1885 glyphs[g->base-1] = og;
1891 static void SecondReorder_Pref_precede_base(const IndicSyllable *s,
1892 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1894 if (s->pref >= 0 && g->pref > g->base)
1896 int j;
1897 WCHAR og = glyphs[g->pref];
1898 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1899 for (j = g->pref; j > g->base; j--)
1900 glyphs[j] = glyphs[j-1];
1901 glyphs[g->base] = og;
1905 static void Reorder_Like_Sinhala(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1907 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1908 if (s->start == s->base && s->base == s->end) return;
1909 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1911 Reorder_Ra_follows_base(pwChar, s, lexical);
1912 Reorder_Matra_precede_base(pwChar, s, lexical);
1915 static void Reorder_Like_Devanagari(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1917 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1918 if (s->start == s->base && s->base == s->end) return;
1919 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1921 Reorder_Ra_follows_matra(pwChar, s, lexical);
1922 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1925 static void Reorder_Like_Bengali(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1927 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1928 if (s->start == s->base && s->base == s->end) return;
1929 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1931 Reorder_Ra_follows_base(pwChar, s, lexical);
1932 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1935 static void Reorder_Like_Kannada(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1937 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1938 if (s->start == s->base && s->base == s->end) return;
1939 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1941 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1942 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1945 static void SecondReorder_Like_Telugu(const WCHAR *chars, const IndicSyllable *s,
1946 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1948 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1949 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1950 if (s->start == s->base && s->base == s->end) return;
1951 if (lexical(chars[s->base]) == lex_Vowel) return;
1953 SecondReorder_Blwf_follows_matra(chars, s, glyphs, g, lexical);
1956 static void SecondReorder_Like_Tamil(const WCHAR *chars, const IndicSyllable *s,
1957 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1959 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1960 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1961 if (s->start == s->base && s->base == s->end) return;
1962 if (lexical(chars[s->base]) == lex_Vowel) return;
1964 SecondReorder_Matra_precede_base(chars, s, glyphs, g, lexical);
1965 SecondReorder_Pref_precede_base(s, glyphs, g, lexical);
1969 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1971 if (shift == 0)
1972 return;
1974 if (glyph_index->start > index)
1975 glyph_index->start += shift;
1976 if (glyph_index->base > index)
1977 glyph_index->base+= shift;
1978 if (glyph_index->end > index)
1979 glyph_index->end+= shift;
1980 if (glyph_index->ralf > index)
1981 glyph_index->ralf+= shift;
1982 if (glyph_index->blwf > index)
1983 glyph_index->blwf+= shift;
1984 if (glyph_index->pref > index)
1985 glyph_index->pref+= shift;
1988 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 )
1990 int index = glyph_index->start;
1992 if (!feature)
1993 return;
1995 while(index <= glyph_index->end)
1997 INT nextIndex;
1998 INT prevCount = *pcGlyphs;
1999 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2000 if (nextIndex > GSUB_E_NOGLYPH)
2002 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2003 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2004 index = nextIndex;
2006 else
2007 index++;
2011 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2013 int i = 0;
2014 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)))))
2015 i++;
2016 if (index + i <= end-1)
2017 return index + i;
2018 else
2019 return -1;
2022 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)
2024 INT index, nextIndex;
2025 INT count,g_offset;
2027 count = syllable->base - syllable->start;
2029 g_offset = 0;
2030 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2031 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2033 INT prevCount = *pcGlyphs;
2034 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2035 if (nextIndex > GSUB_E_NOGLYPH)
2037 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2038 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2039 g_offset += (*pcGlyphs - prevCount);
2042 index+=2;
2043 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2047 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)
2049 INT nextIndex;
2050 INT prevCount = *pcGlyphs;
2052 if (syllable->ralf >= 0)
2054 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2055 if (nextIndex > GSUB_E_NOGLYPH)
2057 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2058 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2063 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2065 int i = 0;
2066 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2067 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2068 is_consonant(lexical(pwChars[index+i+1])))))
2069 i++;
2070 if (index + i <= end-1)
2071 return index+i;
2072 else
2073 return -1;
2076 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)
2078 INT index, nextIndex;
2079 INT count, g_offset=0;
2080 INT ralf = syllable->ralf;
2082 count = syllable->end - syllable->base;
2084 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2086 while (index >= 0)
2088 INT prevCount = *pcGlyphs;
2089 if (ralf >=0 && ralf < index)
2091 g_offset--;
2092 ralf = -1;
2095 if (!modern)
2097 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2098 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2099 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2102 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2103 if (nextIndex > GSUB_E_NOGLYPH)
2105 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2106 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2107 g_offset += (*pcGlyphs - prevCount);
2109 else if (!modern)
2111 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2112 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2113 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2116 index+=2;
2117 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2121 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)
2123 int c;
2124 int overall_shift = 0;
2125 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2126 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2127 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2128 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2129 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2130 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2131 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2132 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2133 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2134 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2135 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2136 IndicSyllable glyph_indexs;
2138 for (c = 0; c < syllable_count; c++)
2140 int old_end;
2141 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2142 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2143 old_end = glyph_indexs.end;
2145 if (locl)
2147 TRACE("applying feature locl\n");
2148 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2150 if (nukt)
2152 TRACE("applying feature nukt\n");
2153 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2155 if (akhn)
2157 TRACE("applying feature akhn\n");
2158 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2161 if (rphf)
2162 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2163 if (rkrf)
2165 TRACE("applying feature rkrf\n");
2166 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2168 if (pref)
2169 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2170 if (blwf)
2172 if (!modern)
2173 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2175 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2178 if (half)
2179 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2180 if (pstf)
2182 TRACE("applying feature pstf\n");
2183 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2185 if (vatu)
2187 TRACE("applying feature vatu\n");
2188 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2190 if (cjct)
2192 TRACE("applying feature cjct\n");
2193 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2196 if (second_reorder)
2197 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2199 overall_shift += glyph_indexs.end - old_end;
2203 static inline int unicode_lex(WCHAR c)
2205 int type;
2207 if (!c) return lex_Generic;
2208 if (c == 0x200D) return lex_ZWJ;
2209 if (c == 0x200C) return lex_ZWNJ;
2210 if (c == 0x00A0) return lex_NBSP;
2212 type = get_table_entry( indic_syllabic_table, c );
2214 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2216 switch( type )
2218 case 0x0d07: /* Unknown */
2219 case 0x0e07: /* Unknown */
2220 default: return lex_Generic;
2221 case 0x0001:
2222 case 0x0002:
2223 case 0x0011:
2224 case 0x0012:
2225 case 0x0013:
2226 case 0x0014: return lex_Modifier;
2227 case 0x0003:
2228 case 0x0009:
2229 case 0x000a:
2230 case 0x000b:
2231 case 0x000d:
2232 case 0x000e:
2233 case 0x000f:
2234 case 0x0010: return lex_Consonant;
2235 case 0x0004: return lex_Nukta;
2236 case 0x0005: return lex_Halant;
2237 case 0x0006:
2238 case 0x0008: return lex_Vowel;
2239 case 0x0007:
2240 case 0x0107: return lex_Matra_post;
2241 case 0x0207:
2242 case 0x0307: return lex_Matra_pre;
2243 case 0x0807:
2244 case 0x0907:
2245 case 0x0a07:
2246 case 0x0b07:
2247 case 0x0c07:
2248 case 0x0407: return lex_Composed_Vowel;
2249 case 0x0507: return lex_Matra_above;
2250 case 0x0607: return lex_Matra_below;
2251 case 0x000c:
2252 case 0x0015: return lex_Ra;
2256 static int sinhala_lex(WCHAR c)
2258 switch (c)
2260 case 0x0DDA:
2261 case 0x0DDD:
2262 case 0x0DDC:
2263 case 0x0DDE: return lex_Matra_post;
2264 default:
2265 return unicode_lex(c);
2269 static const VowelComponents Sinhala_vowels[] = {
2270 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2271 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2272 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2273 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2274 {0x0000, {0x0000,0x0000,0x0}}};
2276 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2278 int cCount = cChars;
2279 int i;
2280 WCHAR *input;
2281 IndicSyllable *syllables = NULL;
2282 int syllable_count = 0;
2284 if (*pcGlyphs != cChars)
2286 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2287 return;
2290 input = heap_alloc(3 * cChars * sizeof(*input));
2292 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2294 /* Step 1: Decompose multi part vowels */
2295 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2297 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2299 /* Step 2: Reorder within Syllables */
2300 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2301 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2303 /* Step 3: Strip dangling joiners */
2304 for (i = 0; i < cCount; i++)
2306 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2307 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2308 input[i] = 0x0020;
2311 /* Step 4: Base Form application to syllables */
2312 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2313 *pcGlyphs = cCount;
2314 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2316 heap_free(input);
2317 heap_free(syllables);
2320 static int devanagari_lex(WCHAR c)
2322 switch (c)
2324 case 0x0930: return lex_Ra;
2325 default:
2326 return unicode_lex(c);
2330 static const ConsonantComponents Devanagari_consonants[] ={
2331 {{0x0928, 0x093C, 0x00000}, 0x0929},
2332 {{0x0930, 0x093C, 0x00000}, 0x0931},
2333 {{0x0933, 0x093C, 0x00000}, 0x0934},
2334 {{0x0915, 0x093C, 0x00000}, 0x0958},
2335 {{0x0916, 0x093C, 0x00000}, 0x0959},
2336 {{0x0917, 0x093C, 0x00000}, 0x095A},
2337 {{0x091C, 0x093C, 0x00000}, 0x095B},
2338 {{0x0921, 0x093C, 0x00000}, 0x095C},
2339 {{0x0922, 0x093C, 0x00000}, 0x095D},
2340 {{0x092B, 0x093C, 0x00000}, 0x095E},
2341 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2343 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2345 int cCount = cChars;
2346 WCHAR *input;
2347 IndicSyllable *syllables = NULL;
2348 int syllable_count = 0;
2349 BOOL modern = get_GSUB_Indic2(psa, psc);
2351 if (*pcGlyphs != cChars)
2353 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2354 return;
2357 input = heap_alloc(cChars * sizeof(*input));
2358 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2360 /* Step 1: Compose Consonant and Nukta */
2361 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2362 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2364 /* Step 2: Reorder within Syllables */
2365 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2366 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2367 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2368 *pcGlyphs = cCount;
2370 /* Step 3: Base Form application to syllables */
2371 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2373 heap_free(input);
2374 heap_free(syllables);
2377 static int bengali_lex(WCHAR c)
2379 switch (c)
2381 case 0x09B0: return lex_Ra;
2382 default:
2383 return unicode_lex(c);
2387 static const VowelComponents Bengali_vowels[] = {
2388 {0x09CB, {0x09C7,0x09BE,0x0000}},
2389 {0x09CC, {0x09C7,0x09D7,0x0000}},
2390 {0x0000, {0x0000,0x0000,0x0000}}};
2392 static const ConsonantComponents Bengali_consonants[] = {
2393 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2394 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2395 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2396 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2397 {{0x0000,0x0000,0x0000}, 0x0000}};
2399 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2401 int cCount = cChars;
2402 WCHAR *input;
2403 IndicSyllable *syllables = NULL;
2404 int syllable_count = 0;
2405 BOOL modern = get_GSUB_Indic2(psa, psc);
2407 if (*pcGlyphs != cChars)
2409 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2410 return;
2413 input = heap_alloc(2 * cChars * sizeof(*input));
2414 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2416 /* Step 1: Decompose Vowels and Compose Consonants */
2417 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2418 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2419 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2421 /* Step 2: Reorder within Syllables */
2422 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2423 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2424 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2425 *pcGlyphs = cCount;
2427 /* Step 3: Initial form is only applied to the beginning of words */
2428 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2430 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2432 int index = cCount;
2433 int gCount = 1;
2434 if (index > 0) index++;
2436 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2440 /* Step 4: Base Form application to syllables */
2441 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2443 heap_free(input);
2444 heap_free(syllables);
2447 static int gurmukhi_lex(WCHAR c)
2449 if (c == 0x0A71)
2450 return lex_Modifier;
2451 else
2452 return unicode_lex(c);
2455 static const ConsonantComponents Gurmukhi_consonants[] = {
2456 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2457 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2458 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2459 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2460 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2461 {{0x0000,0x0000,0x0000}, 0x0000}};
2463 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2465 int cCount = cChars;
2466 WCHAR *input;
2467 IndicSyllable *syllables = NULL;
2468 int syllable_count = 0;
2469 BOOL modern = get_GSUB_Indic2(psa, psc);
2471 if (*pcGlyphs != cChars)
2473 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2474 return;
2477 input = heap_alloc(cChars * sizeof(*input));
2478 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2480 /* Step 1: Compose Consonants */
2481 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2482 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2484 /* Step 2: Reorder within Syllables */
2485 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2486 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2487 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2488 *pcGlyphs = cCount;
2490 /* Step 3: Base Form application to syllables */
2491 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2493 heap_free(input);
2494 heap_free(syllables);
2497 static int gujarati_lex(WCHAR c)
2499 switch (c)
2501 case 0x0AB0: return lex_Ra;
2502 default:
2503 return unicode_lex(c);
2507 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2509 int cCount = cChars;
2510 WCHAR *input;
2511 IndicSyllable *syllables = NULL;
2512 int syllable_count = 0;
2513 BOOL modern = get_GSUB_Indic2(psa, psc);
2515 if (*pcGlyphs != cChars)
2517 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2518 return;
2521 input = heap_alloc(cChars * sizeof(*input));
2522 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2524 /* Step 1: Reorder within Syllables */
2525 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2526 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2527 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2528 *pcGlyphs = cCount;
2530 /* Step 2: Base Form application to syllables */
2531 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2533 heap_free(input);
2534 heap_free(syllables);
2537 static int oriya_lex(WCHAR c)
2539 switch (c)
2541 case 0x0B30: return lex_Ra;
2542 default:
2543 return unicode_lex(c);
2547 static const VowelComponents Oriya_vowels[] = {
2548 {0x0B48, {0x0B47,0x0B56,0x0000}},
2549 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2550 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2551 {0x0000, {0x0000,0x0000,0x0000}}};
2553 static const ConsonantComponents Oriya_consonants[] = {
2554 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2555 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2556 {{0x0000,0x0000,0x0000}, 0x0000}};
2558 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2560 int cCount = cChars;
2561 WCHAR *input;
2562 IndicSyllable *syllables = NULL;
2563 int syllable_count = 0;
2564 BOOL modern = get_GSUB_Indic2(psa, psc);
2566 if (*pcGlyphs != cChars)
2568 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2569 return;
2572 input = heap_alloc(2 * cChars * sizeof(*input));
2573 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2575 /* Step 1: Decompose Vowels and Compose Consonants */
2576 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2577 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2578 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2580 /* Step 2: Reorder within Syllables */
2581 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2582 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2583 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2584 *pcGlyphs = cCount;
2586 /* Step 3: Base Form application to syllables */
2587 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2589 heap_free(input);
2590 heap_free(syllables);
2593 static int tamil_lex(WCHAR c)
2595 return unicode_lex(c);
2598 static const VowelComponents Tamil_vowels[] = {
2599 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2600 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2601 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2602 {0x0000, {0x0000,0x0000,0x0000}}};
2604 static const ConsonantComponents Tamil_consonants[] = {
2605 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2606 {{0x0000,0x0000,0x0000}, 0x0000}};
2608 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2610 int cCount = cChars;
2611 WCHAR *input;
2612 IndicSyllable *syllables = NULL;
2613 int syllable_count = 0;
2614 BOOL modern = get_GSUB_Indic2(psa, psc);
2616 if (*pcGlyphs != cChars)
2618 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2619 return;
2622 input = heap_alloc(2 * cChars * sizeof(*input));
2623 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2625 /* Step 1: Decompose Vowels and Compose Consonants */
2626 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2627 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2628 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2630 /* Step 2: Reorder within Syllables */
2631 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2632 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2633 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2634 *pcGlyphs = cCount;
2636 /* Step 3: Base Form application to syllables */
2637 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2639 heap_free(input);
2640 heap_free(syllables);
2643 static int telugu_lex(WCHAR c)
2645 switch (c)
2647 case 0x0C43:
2648 case 0x0C44: return lex_Modifier;
2649 default:
2650 return unicode_lex(c);
2654 static const VowelComponents Telugu_vowels[] = {
2655 {0x0C48, {0x0C46,0x0C56,0x0000}},
2656 {0x0000, {0x0000,0x0000,0x0000}}};
2658 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2660 int cCount = cChars;
2661 WCHAR *input;
2662 IndicSyllable *syllables = NULL;
2663 int syllable_count = 0;
2664 BOOL modern = get_GSUB_Indic2(psa, psc);
2666 if (*pcGlyphs != cChars)
2668 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2669 return;
2672 input = heap_alloc(2 * cChars * sizeof(*input));
2673 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2675 /* Step 1: Decompose Vowels */
2676 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2677 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2679 /* Step 2: Reorder within Syllables */
2680 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2681 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2682 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2683 *pcGlyphs = cCount;
2685 /* Step 3: Base Form application to syllables */
2686 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2688 heap_free(input);
2689 heap_free(syllables);
2692 static int kannada_lex(WCHAR c)
2694 switch (c)
2696 case 0x0CB0: return lex_Ra;
2697 default:
2698 return unicode_lex(c);
2702 static const VowelComponents Kannada_vowels[] = {
2703 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2704 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2705 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2706 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2707 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2708 {0x0000, {0x0000,0x0000,0x0000}}};
2710 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2712 int cCount = cChars;
2713 WCHAR *input;
2714 IndicSyllable *syllables = NULL;
2715 int syllable_count = 0;
2716 BOOL modern = get_GSUB_Indic2(psa, psc);
2718 if (*pcGlyphs != cChars)
2720 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2721 return;
2724 input = heap_alloc(3 * cChars * sizeof(*input));
2725 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2727 /* Step 1: Decompose Vowels */
2728 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2729 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2731 /* Step 2: Reorder within Syllables */
2732 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2733 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2734 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2735 *pcGlyphs = cCount;
2737 /* Step 3: Base Form application to syllables */
2738 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2740 heap_free(input);
2741 heap_free(syllables);
2744 static int malayalam_lex(WCHAR c)
2746 return unicode_lex(c);
2749 static const VowelComponents Malayalam_vowels[] = {
2750 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2751 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2752 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2753 {0x0000, {0x0000,0x0000,0x0000}}};
2755 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2757 int cCount = cChars;
2758 WCHAR *input;
2759 IndicSyllable *syllables = NULL;
2760 int syllable_count = 0;
2761 BOOL modern = get_GSUB_Indic2(psa, psc);
2763 if (*pcGlyphs != cChars)
2765 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2766 return;
2769 input = heap_alloc(2 * cChars * sizeof(*input));
2770 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2772 /* Step 1: Decompose Vowels */
2773 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2774 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2776 /* Step 2: Reorder within Syllables */
2777 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2778 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2779 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2780 *pcGlyphs = cCount;
2782 /* Step 3: Base Form application to syllables */
2783 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2785 heap_free(input);
2786 heap_free(syllables);
2789 static int khmer_lex(WCHAR c)
2791 return unicode_lex(c);
2794 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2796 int cCount = cChars;
2797 WCHAR *input;
2798 IndicSyllable *syllables = NULL;
2799 int syllable_count = 0;
2801 if (*pcGlyphs != cChars)
2803 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2804 return;
2807 input = heap_alloc(cChars * sizeof(*input));
2808 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2810 /* Step 1: Reorder within Syllables */
2811 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2812 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2813 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2814 *pcGlyphs = cCount;
2816 /* Step 2: Base Form application to syllables */
2817 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2819 heap_free(input);
2820 heap_free(syllables);
2823 static inline BOOL mongolian_wordbreak(WCHAR chr)
2825 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2828 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2830 INT *context_shape;
2831 INT dirL;
2832 int i;
2833 int char_index;
2834 int glyph_index;
2836 if (*pcGlyphs != cChars)
2838 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2839 return;
2842 if (!psa->fLogicalOrder && psa->fRTL)
2843 dirL = -1;
2844 else
2845 dirL = 1;
2847 if (!psc->GSUB_Table)
2848 return;
2850 context_shape = heap_alloc(cChars * sizeof(*context_shape));
2852 for (i = 0; i < cChars; i++)
2854 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2856 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2857 context_shape[i] = Xn;
2858 else
2859 context_shape[i] = Xl;
2861 else
2863 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2864 context_shape[i] = Xr;
2865 else
2866 context_shape[i] = Xm;
2870 /* Contextual Shaping */
2871 if (dirL > 0)
2872 char_index = glyph_index = 0;
2873 else
2874 char_index = glyph_index = cChars-1;
2876 while(char_index < cChars && char_index >= 0)
2878 INT nextIndex;
2879 INT prevCount = *pcGlyphs;
2880 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2882 if (nextIndex > GSUB_E_NOGLYPH)
2884 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2885 glyph_index = nextIndex;
2886 char_index += dirL;
2888 else
2890 char_index += dirL;
2891 glyph_index += dirL;
2895 heap_free(context_shape);
2898 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)
2900 int i,k;
2902 for (i = 0; i < cGlyphs; i++)
2904 int char_index[20];
2905 int char_count = 0;
2907 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2908 if (k>=0)
2910 for (; k < cChars && pwLogClust[k] == i; k++)
2911 char_index[char_count++] = k;
2914 if (char_count == 0)
2915 continue;
2917 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2919 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2920 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2922 else
2923 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2926 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2927 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2930 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2932 int i;
2934 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2936 for (i = 0; i < cGlyphs; i++)
2937 if (pGlyphProp[i].sva.fZeroWidth)
2938 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2941 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2943 int i;
2944 for (i = 0; i < cGlyphs; i++)
2946 pGlyphProp[i].sva.fClusterStart = 1;
2947 pGlyphProp[i].sva.fDiacritic = 0;
2948 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2950 if (pwGlyphs[i] == psc->sfp.wgDefault)
2951 pGlyphProp[i].sva.fZeroWidth = 0;
2952 else
2953 pGlyphProp[i].sva.fZeroWidth = 1;
2957 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 )
2959 int i,k;
2960 int initGlyph, finaGlyph;
2961 INT dirR, dirL;
2962 BYTE *spaces;
2964 spaces = heap_alloc(cGlyphs);
2965 memset(spaces,0,cGlyphs);
2967 if (psa->fLogicalOrder && psa->fRTL)
2969 initGlyph = 0;
2970 finaGlyph = cGlyphs-1;
2971 dirR = -1;
2972 dirL = 1;
2974 else
2976 initGlyph = cGlyphs-1;
2977 finaGlyph = 0;
2978 dirR = 1;
2979 dirL = -1;
2982 for (i = 0; i < cGlyphs; i++)
2984 for (k = 0; k < cChars; k++)
2985 if (pwLogClust[k] == i)
2987 if (pwcChars[k] == 0x0020)
2988 spaces[i] = 1;
2992 for (i = 0; i < cGlyphs; i++)
2994 int char_index[20];
2995 int char_count = 0;
2996 BOOL isInit, isFinal;
2998 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2999 if (k>=0)
3001 for (; k < cChars && pwLogClust[k] == i; k++)
3002 char_index[char_count++] = k;
3005 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3006 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3008 if (char_count == 0)
3009 continue;
3011 if (char_count == 1)
3013 if (pwcChars[char_index[0]] == 0x0020) /* space */
3015 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3016 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3018 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3019 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3020 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3022 if (!isInit && !isFinal)
3023 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3024 else if (isInit)
3025 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3026 else
3027 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3029 else if (!isInit)
3031 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3032 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3033 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3034 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3035 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3036 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3037 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3038 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3039 else
3040 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3042 else if (!isInit && !isFinal)
3043 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3044 else
3045 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3047 else if (char_count == 2)
3049 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3050 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3051 else if (!isInit)
3052 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3053 else
3054 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3056 else if (!isInit && !isFinal)
3057 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3058 else
3059 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3062 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3063 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3064 heap_free(spaces);
3067 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 )
3069 int i,k;
3071 for (i = 0; i < cGlyphs; i++)
3073 int char_index[20];
3074 int char_count = 0;
3076 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3077 if (k>=0)
3079 for (; k < cChars && pwLogClust[k] == i; k++)
3080 char_index[char_count++] = k;
3083 if (char_count == 0)
3084 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3085 else
3087 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3088 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3089 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3093 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3094 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3097 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 )
3099 int i;
3100 int finaGlyph;
3101 INT dirL;
3103 if (!psa->fLogicalOrder && psa->fRTL)
3105 finaGlyph = 0;
3106 dirL = -1;
3108 else
3110 finaGlyph = cGlyphs-1;
3111 dirL = 1;
3114 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3116 for (i = 0; i < cGlyphs; i++)
3118 int k;
3119 int char_index[20];
3120 int char_count = 0;
3122 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3123 if (k>=0)
3125 for (; k < cChars && pwLogClust[k] == i; k++)
3126 char_index[char_count++] = k;
3129 if (i == finaGlyph)
3130 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3131 else
3132 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3134 if (char_count == 0)
3135 continue;
3137 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3138 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3140 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3141 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3142 pGlyphProp[i].sva.fClusterStart = 0;
3145 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3147 /* Do not allow justification between marks and their base */
3148 for (i = 0; i < cGlyphs; i++)
3150 if (!pGlyphProp[i].sva.fClusterStart)
3151 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3155 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)
3157 int i,k;
3159 for (i = 0; i < cGlyphs; i++)
3161 int char_index[20];
3162 int char_count = 0;
3164 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3165 if (k>=0)
3167 for (; k < cChars && pwLogClust[k] == i; k++)
3168 char_index[char_count++] = k;
3171 if (char_count == 0)
3172 continue;
3174 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3176 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3177 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3179 else
3180 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3182 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3183 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3186 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)
3188 int i,k;
3190 for (i = 0; i < cGlyphs; i++)
3192 int char_index[20];
3193 int char_count = 0;
3195 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3196 if (k>=0)
3198 for (; k < cChars && pwLogClust[k] == i; k++)
3199 char_index[char_count++] = k;
3202 if (char_count == 0)
3203 continue;
3205 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3207 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3208 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3210 else
3211 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3213 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3214 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3216 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3217 for (i = 0; i < cGlyphs; i++)
3219 if (!pGlyphProp[i].sva.fClusterStart)
3221 pGlyphProp[i].sva.fDiacritic = 0;
3222 pGlyphProp[i].sva.fZeroWidth = 0;
3227 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)
3229 int i,k;
3231 OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3232 for (i = 0; i < cGlyphs; i++)
3234 int char_index[20];
3235 int char_count = 0;
3237 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3238 if (k>=0)
3240 for (; k < cChars && pwLogClust[k] == i; k++)
3241 char_index[char_count++] = k;
3244 if (override_gsub)
3246 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3247 pGlyphProp[i].sva.fDiacritic = FALSE;
3248 pGlyphProp[i].sva.fZeroWidth = FALSE;
3251 if (char_count == 0)
3253 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3254 continue;
3257 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3259 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3260 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3262 else
3263 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3265 pGlyphProp[i].sva.fClusterStart = 0;
3266 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3267 switch (lexical(pwcChars[char_index[k]]))
3269 case lex_Matra_pre:
3270 case lex_Matra_post:
3271 case lex_Matra_above:
3272 case lex_Matra_below:
3273 case lex_Modifier:
3274 case lex_Halant:
3275 break;
3276 case lex_ZWJ:
3277 case lex_ZWNJ:
3278 /* check for dangling joiners */
3279 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3280 pGlyphProp[i].sva.fClusterStart = 1;
3281 else
3282 k = char_count;
3283 break;
3284 default:
3285 pGlyphProp[i].sva.fClusterStart = 1;
3286 break;
3290 if (use_syllables)
3292 IndicSyllable *syllables = NULL;
3293 int syllable_count = 0;
3294 BOOL modern = get_GSUB_Indic2(psa, psc);
3296 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3298 for (i = 0; i < syllable_count; i++)
3300 int j;
3301 WORD g = pwLogClust[syllables[i].start];
3302 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3304 if (pwLogClust[j] != g)
3306 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3307 pwLogClust[j] = g;
3312 heap_free(syllables);
3315 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3318 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 )
3320 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3323 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 )
3325 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3328 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 )
3330 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3333 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 )
3335 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3338 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 )
3340 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3343 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 )
3345 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3348 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 )
3350 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3353 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 )
3355 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3358 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 )
3360 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3363 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 )
3365 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3368 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 )
3370 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3373 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)
3375 load_ot_tables(hdc, psc);
3377 if (ShapingData[psa->eScript].charGlyphPropProc)
3378 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3379 else
3380 ShapeCharGlyphProp_Default(psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3383 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3385 load_ot_tables(hdc, psc);
3387 if (ShapingData[psa->eScript].contextProc)
3388 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3391 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)
3393 int i;
3394 INT dirL;
3396 if (!rpRangeProperties)
3397 return;
3399 load_ot_tables(hdc, psc);
3401 if (!psc->GSUB_Table)
3402 return;
3404 if (scriptInformation[psa->eScript].a.fRTL && (!psa->fLogicalOrder || !psa->fRTL))
3405 dirL = -1;
3406 else
3407 dirL = 1;
3409 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3411 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3412 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3416 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3418 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3419 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3421 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3424 void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset )
3426 const TEXTRANGE_PROPERTIES *rpRangeProperties = &ShapingData[psa->eScript].defaultGPOSTextRange;
3427 int i;
3429 load_ot_tables(hdc, psc);
3431 if (!psc->GPOS_Table || !psc->otm)
3432 return;
3434 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3436 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3438 LoadedFeature *feature;
3440 feature = load_OT_feature(hdc, psa, psc, FEATURE_GPOS_TABLE, (const char*)&rpRangeProperties->potfRecords[i].tagFeature);
3441 if (!feature)
3442 continue;
3444 GPOS_apply_feature(psc, psc->otm, &psc->lf, psa, piAdvance, feature, pwGlyphs, cGlyphs, pGoffset);
3449 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3451 LoadedFeature *feature;
3452 int i;
3454 if (!ShapingData[psa->eScript].requiredFeatures)
3455 return S_OK;
3457 load_ot_tables(hdc, psc);
3459 /* we need to have at least one of the required features */
3460 i = 0;
3461 while (ShapingData[psa->eScript].requiredFeatures[i])
3463 feature = load_OT_feature(hdc, psa, psc, FEATURE_ALL_TABLES, ShapingData[psa->eScript].requiredFeatures[i]);
3464 if (feature)
3465 return S_OK;
3466 i++;
3469 return USP_E_SCRIPT_NOT_IN_FONT;
3472 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3473 SCRIPT_ANALYSIS *psa, int cMaxTags,
3474 OPENTYPE_TAG *pScriptTags, int *pcTags)
3476 HRESULT hr;
3477 OPENTYPE_TAG searching = 0x00000000;
3479 load_ot_tables(hdc, psc);
3481 if (psa && scriptInformation[psa->eScript].scriptTag)
3482 searching = scriptInformation[psa->eScript].scriptTag;
3484 hr = OpenType_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags);
3485 if (FAILED(hr))
3486 *pcTags = 0;
3487 return hr;
3490 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3491 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3492 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3493 int *pcTags)
3495 HRESULT hr;
3496 OPENTYPE_TAG searching = 0x00000000;
3497 BOOL fellback = FALSE;
3499 load_ot_tables(hdc, psc);
3501 if (psa && psc->userLang != 0)
3502 searching = psc->userLang;
3504 hr = OpenType_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags);
3505 if (FAILED(hr))
3507 fellback = TRUE;
3508 hr = OpenType_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags);
3511 if (FAILED(hr) || fellback)
3512 *pcTags = 0;
3513 if (SUCCEEDED(hr) && fellback && psa)
3514 hr = E_INVALIDARG;
3515 return hr;
3518 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3519 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3520 OPENTYPE_TAG tagLangSys, int cMaxTags,
3521 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3523 HRESULT hr;
3524 BOOL filter = FALSE;
3526 load_ot_tables(hdc, psc);
3528 if (psa && scriptInformation[psa->eScript].scriptTag)
3530 FIXME("Filtering not implemented\n");
3531 filter = TRUE;
3534 hr = OpenType_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, FEATURE_ALL_TABLES, cMaxTags, pFeatureTags, pcTags, NULL);
3536 if (FAILED(hr))
3537 *pcTags = 0;
3538 return hr;