usp10: Non modern Indic fonts want blwf applied pre and post base.
[wine/multimedia.git] / dlls / usp10 / shape.c
blob8152e336d1e5ffb20b1c63141866a06e727fa9cf
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>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "usp10.h"
29 #include "winternl.h"
31 #include "usp10_internal.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
37 #define FIRST_ARABIC_CHAR 0x0600
38 #define LAST_ARABIC_CHAR 0x06ff
40 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
41 WCHAR*, INT, WORD*, INT*, INT, WORD*);
43 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
59 static void ShapeCharGlyphProp_Default( 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);
60 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 );
61 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 );
62 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 );
63 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 );
64 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 );
65 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 );
66 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 );
67 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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
74 extern const unsigned short wine_shaping_table[];
75 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
77 enum joining_types {
78 jtU,
79 jtT,
80 jtR,
81 jtL,
82 jtD,
83 jtC
86 enum joined_forms {
87 Xn=0,
88 Xr,
89 Xl,
90 Xm,
91 /* Syriac Alaph */
92 Afj,
93 Afn,
94 Afx
97 #ifdef WORDS_BIGENDIAN
98 #define GET_BE_WORD(x) (x)
99 #else
100 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
101 #endif
103 /* These are all structures needed for the GSUB table */
104 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
105 #define GSUB_E_NOFEATURE -2
106 #define GSUB_E_NOGLYPH -1
108 typedef struct {
109 DWORD version;
110 WORD ScriptList;
111 WORD FeatureList;
112 WORD LookupList;
113 } GSUB_Header;
115 typedef struct {
116 CHAR ScriptTag[4];
117 WORD Script;
118 } GSUB_ScriptRecord;
120 typedef struct {
121 WORD ScriptCount;
122 GSUB_ScriptRecord ScriptRecord[1];
123 } GSUB_ScriptList;
125 typedef struct {
126 CHAR LangSysTag[4];
127 WORD LangSys;
128 } GSUB_LangSysRecord;
130 typedef struct {
131 WORD DefaultLangSys;
132 WORD LangSysCount;
133 GSUB_LangSysRecord LangSysRecord[1];
134 } GSUB_Script;
136 typedef struct {
137 WORD LookupOrder; /* Reserved */
138 WORD ReqFeatureIndex;
139 WORD FeatureCount;
140 WORD FeatureIndex[1];
141 } GSUB_LangSys;
143 typedef struct {
144 CHAR FeatureTag[4];
145 WORD Feature;
146 } GSUB_FeatureRecord;
148 typedef struct {
149 WORD FeatureCount;
150 GSUB_FeatureRecord FeatureRecord[1];
151 } GSUB_FeatureList;
153 typedef struct {
154 WORD FeatureParams; /* Reserved */
155 WORD LookupCount;
156 WORD LookupListIndex[1];
157 } GSUB_Feature;
159 typedef struct {
160 WORD LookupCount;
161 WORD Lookup[1];
162 } GSUB_LookupList;
164 typedef struct {
165 WORD LookupType;
166 WORD LookupFlag;
167 WORD SubTableCount;
168 WORD SubTable[1];
169 } GSUB_LookupTable;
171 typedef struct {
172 WORD CoverageFormat;
173 WORD GlyphCount;
174 WORD GlyphArray[1];
175 } GSUB_CoverageFormat1;
177 typedef struct {
178 WORD Start;
179 WORD End;
180 WORD StartCoverageIndex;
181 } GSUB_RangeRecord;
183 typedef struct {
184 WORD CoverageFormat;
185 WORD RangeCount;
186 GSUB_RangeRecord RangeRecord[1];
187 } GSUB_CoverageFormat2;
189 typedef struct {
190 WORD SubstFormat; /* = 1 */
191 WORD Coverage;
192 WORD DeltaGlyphID;
193 } GSUB_SingleSubstFormat1;
195 typedef struct {
196 WORD SubstFormat; /* = 2 */
197 WORD Coverage;
198 WORD GlyphCount;
199 WORD Substitute[1];
200 }GSUB_SingleSubstFormat2;
202 typedef struct {
203 WORD SubstFormat; /* = 1 */
204 WORD Coverage;
205 WORD LigSetCount;
206 WORD LigatureSet[1];
207 }GSUB_LigatureSubstFormat1;
209 typedef struct {
210 WORD LigatureCount;
211 WORD Ligature[1];
212 }GSUB_LigatureSet;
214 typedef struct{
215 WORD LigGlyph;
216 WORD CompCount;
217 WORD Component[1];
218 }GSUB_Ligature;
220 typedef struct{
221 WORD SequenceIndex;
222 WORD LookupListIndex;
224 }GSUB_SubstLookupRecord;
226 typedef struct{
227 WORD SubstFormat; /* = 1 */
228 WORD Coverage;
229 WORD ChainSubRuleSetCount;
230 WORD ChainSubRuleSet[1];
231 }GSUB_ChainContextSubstFormat1;
233 typedef struct {
234 WORD SubstFormat; /* = 3 */
235 WORD BacktrackGlyphCount;
236 WORD Coverage[1];
237 }GSUB_ChainContextSubstFormat3_1;
239 typedef struct{
240 WORD InputGlyphCount;
241 WORD Coverage[1];
242 }GSUB_ChainContextSubstFormat3_2;
244 typedef struct{
245 WORD LookaheadGlyphCount;
246 WORD Coverage[1];
247 }GSUB_ChainContextSubstFormat3_3;
249 typedef struct{
250 WORD SubstCount;
251 GSUB_SubstLookupRecord SubstLookupRecord[1];
252 }GSUB_ChainContextSubstFormat3_4;
254 typedef struct {
255 WORD SubstFormat; /* = 1 */
256 WORD Coverage;
257 WORD AlternateSetCount;
258 WORD AlternateSet[1];
259 } GSUB_AlternateSubstFormat1;
261 typedef struct{
262 WORD GlyphCount;
263 WORD Alternate[1];
264 } GSUB_AlternateSet;
266 /* These are all structures needed for the GDEF table */
267 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
269 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
271 typedef struct {
272 DWORD Version;
273 WORD GlyphClassDef;
274 WORD AttachList;
275 WORD LigCaretList;
276 WORD MarkAttachClassDef;
277 } GDEF_Header;
279 typedef struct {
280 WORD ClassFormat;
281 WORD StartGlyph;
282 WORD GlyphCount;
283 WORD ClassValueArray[1];
284 } GDEF_ClassDefFormat1;
286 typedef struct {
287 WORD Start;
288 WORD End;
289 WORD Class;
290 } GDEF_ClassRangeRecord;
292 typedef struct {
293 WORD ClassFormat;
294 WORD ClassRangeCount;
295 GDEF_ClassRangeRecord ClassRangeRecord[1];
296 } GDEF_ClassDefFormat2;
298 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
300 typedef struct tagVowelComponents
302 WCHAR base;
303 WCHAR parts[3];
304 } VowelComponents;
306 typedef struct tagConsonantComponents
308 WCHAR parts[3];
309 WCHAR output;
310 } ConsonantComponents;
312 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
314 /* the orders of joined_forms and contextual_features need to line up */
315 static const char* contextual_features[] =
317 "isol",
318 "fina",
319 "init",
320 "medi",
321 /* Syriac Alaph */
322 "med2",
323 "fin2",
324 "fin3"
327 static OPENTYPE_FEATURE_RECORD standard_features[] =
329 { MS_MAKE_TAG('l','i','g','a'), 1},
330 { MS_MAKE_TAG('c','l','i','g'), 1},
333 static OPENTYPE_FEATURE_RECORD arabic_features[] =
335 { MS_MAKE_TAG('r','l','i','g'), 1},
336 { MS_MAKE_TAG('c','a','l','t'), 1},
337 { MS_MAKE_TAG('l','i','g','a'), 1},
338 { MS_MAKE_TAG('d','l','i','g'), 1},
339 { MS_MAKE_TAG('c','s','w','h'), 1},
340 { MS_MAKE_TAG('m','s','e','t'), 1},
343 static const char* required_arabic_features[] =
345 "fina",
346 "init",
347 "medi",
348 "rlig",
349 NULL
352 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
354 { MS_MAKE_TAG('d','l','i','g'), 1},
357 static OPENTYPE_FEATURE_RECORD syriac_features[] =
359 { MS_MAKE_TAG('r','l','i','g'), 1},
360 { MS_MAKE_TAG('c','a','l','t'), 1},
361 { MS_MAKE_TAG('l','i','g','a'), 1},
362 { MS_MAKE_TAG('d','l','i','g'), 1},
365 static const char* required_syriac_features[] =
367 "fina",
368 "fin2",
369 "fin3",
370 "init",
371 "medi",
372 "med2",
373 "rlig",
374 NULL
377 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
379 /* Presentation forms */
380 { MS_MAKE_TAG('b','l','w','s'), 1},
381 { MS_MAKE_TAG('a','b','v','s'), 1},
382 { MS_MAKE_TAG('p','s','t','s'), 1},
385 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
387 { MS_MAKE_TAG('a','b','v','s'), 1},
388 { MS_MAKE_TAG('b','l','w','s'), 1},
391 static OPENTYPE_FEATURE_RECORD thai_features[] =
393 { MS_MAKE_TAG('c','c','m','p'), 1},
396 static const char* required_lao_features[] =
398 "ccmp",
399 NULL
402 static const char* required_devanagari_features[] =
404 "nukt",
405 "akhn",
406 "rphf",
407 "blwf",
408 "half",
409 "vatu",
410 "pres",
411 "abvs",
412 "blws",
413 "psts",
414 "haln",
415 NULL
418 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
420 { MS_MAKE_TAG('p','r','e','s'), 1},
421 { MS_MAKE_TAG('a','b','v','s'), 1},
422 { MS_MAKE_TAG('b','l','w','s'), 1},
423 { MS_MAKE_TAG('p','s','t','s'), 1},
424 { MS_MAKE_TAG('h','a','l','n'), 1},
425 { MS_MAKE_TAG('c','a','l','t'), 1},
428 static const char* required_bengali_features[] =
430 "nukt",
431 "akhn",
432 "rphf",
433 "blwf",
434 "half",
435 "vatu",
436 "pstf",
437 "init",
438 "abvs",
439 "blws",
440 "psts",
441 "haln",
442 NULL
445 static const char* required_gurmukhi_features[] =
447 "nukt",
448 "akhn",
449 "rphf",
450 "blwf",
451 "half",
452 "pstf",
453 "vatu",
454 "cjct",
455 "pres",
456 "abvs",
457 "blws",
458 "psts",
459 "haln",
460 "calt",
461 NULL
464 static const char* required_oriya_features[] =
466 "nukt",
467 "akhn",
468 "rphf",
469 "blwf",
470 "pstf",
471 "cjct",
472 "pres",
473 "abvs",
474 "blws",
475 "psts",
476 "haln",
477 "calt",
478 NULL
481 static const char* required_tamil_features[] =
483 "nukt",
484 "akhn",
485 "rphf",
486 "pref",
487 "half",
488 "pres",
489 "abvs",
490 "blws",
491 "psts",
492 "haln",
493 "calt",
494 NULL
497 static const char* required_telugu_features[] =
499 "nukt",
500 "akhn",
501 "rphf",
502 "pref",
503 "half",
504 "pstf",
505 "cjct",
506 "pres",
507 "abvs",
508 "blws",
509 "psts",
510 "haln",
511 "calt",
512 NULL
515 typedef struct ScriptShapeDataTag {
516 TEXTRANGE_PROPERTIES defaultTextRange;
517 const char** requiredFeatures;
518 CHAR otTag[5];
519 CHAR newOtTag[5];
520 ContextualShapingProc contextProc;
521 ShapeCharGlyphPropProc charGlyphPropProc;
522 } ScriptShapeData;
524 /* in order of scripts */
525 static const ScriptShapeData ShapingData[] =
527 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
528 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
529 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
530 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
531 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
532 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
533 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
534 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
535 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
536 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
537 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
538 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
539 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
540 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
541 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
542 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
543 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
544 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
545 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
546 {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
547 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
548 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
549 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
550 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
551 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
552 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
553 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
554 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
555 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
556 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
557 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
558 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
559 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
560 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
561 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
562 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
563 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
564 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
565 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
566 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
567 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
568 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
569 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
572 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
574 const GSUB_CoverageFormat1* cf1;
576 cf1 = table;
578 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
580 int count = GET_BE_WORD(cf1->GlyphCount);
581 int i;
582 TRACE("Coverage Format 1, %i glyphs\n",count);
583 for (i = 0; i < count; i++)
584 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
585 return i;
586 return -1;
588 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
590 const GSUB_CoverageFormat2* cf2;
591 int i;
592 int count;
593 cf2 = (const GSUB_CoverageFormat2*)cf1;
595 count = GET_BE_WORD(cf2->RangeCount);
596 TRACE("Coverage Format 2, %i ranges\n",count);
597 for (i = 0; i < count; i++)
599 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
600 return -1;
601 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
602 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
604 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
605 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
608 return -1;
610 else
611 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
613 return -1;
616 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
618 const GSUB_ScriptList *script;
619 const GSUB_Script *deflt = NULL;
620 int i;
621 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
623 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
624 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
626 const GSUB_Script *scr;
627 int offset;
629 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
630 scr = (const GSUB_Script*)((const BYTE*)script + offset);
632 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
633 return scr;
634 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
635 deflt = scr;
637 return deflt;
640 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
642 int i;
643 int offset;
644 const GSUB_LangSys *Lang;
646 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
648 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
650 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
651 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
653 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
654 return Lang;
656 offset = GET_BE_WORD(script->DefaultLangSys);
657 if (offset)
659 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
660 return Lang;
662 return NULL;
665 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
667 int i;
668 const GSUB_FeatureList *feature;
669 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
671 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
672 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
674 int index = GET_BE_WORD(lang->FeatureIndex[i]);
675 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
677 const GSUB_Feature *feat;
678 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
679 return feat;
682 return NULL;
685 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
687 int j;
688 TRACE("Single Substitution Subtable\n");
690 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
692 int offset;
693 const GSUB_SingleSubstFormat1 *ssf1;
694 offset = GET_BE_WORD(look->SubTable[j]);
695 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
696 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
698 int offset = GET_BE_WORD(ssf1->Coverage);
699 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
700 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
702 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
703 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
704 TRACE(" 0x%x\n",glyphs[glyph_index]);
705 return glyph_index + 1;
708 else
710 const GSUB_SingleSubstFormat2 *ssf2;
711 INT index;
712 INT offset;
714 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
715 offset = GET_BE_WORD(ssf1->Coverage);
716 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
717 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
718 TRACE(" Coverage index %i\n",index);
719 if (index != -1)
721 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
722 return GSUB_E_NOGLYPH;
724 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
725 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
726 TRACE("0x%x\n",glyphs[glyph_index]);
727 return glyph_index + 1;
731 return GSUB_E_NOGLYPH;
734 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
736 int j;
737 TRACE("Alternate Substitution Subtable\n");
739 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
741 int offset;
742 const GSUB_AlternateSubstFormat1 *asf1;
743 INT index;
745 offset = GET_BE_WORD(look->SubTable[j]);
746 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
747 offset = GET_BE_WORD(asf1->Coverage);
749 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
750 if (index != -1)
752 const GSUB_AlternateSet *as;
753 offset = GET_BE_WORD(asf1->AlternateSet[index]);
754 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
755 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
756 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
757 return GSUB_E_NOGLYPH;
759 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
760 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
761 TRACE(" 0x%x\n",glyphs[glyph_index]);
762 return glyph_index + 1;
765 return GSUB_E_NOGLYPH;
768 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
770 int j;
772 TRACE("Ligature Substitution Subtable\n");
773 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
775 const GSUB_LigatureSubstFormat1 *lsf1;
776 int offset,index;
778 offset = GET_BE_WORD(look->SubTable[j]);
779 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
780 offset = GET_BE_WORD(lsf1->Coverage);
781 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
782 TRACE(" Coverage index %i\n",index);
783 if (index != -1)
785 const GSUB_LigatureSet *ls;
786 int k, count;
788 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
789 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
790 count = GET_BE_WORD(ls->LigatureCount);
791 TRACE(" LigatureSet has %i members\n",count);
792 for (k = 0; k < count; k++)
794 const GSUB_Ligature *lig;
795 int CompCount,l,CompIndex;
797 offset = GET_BE_WORD(ls->Ligature[k]);
798 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
799 CompCount = GET_BE_WORD(lig->CompCount) - 1;
800 CompIndex = glyph_index+write_dir;
801 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
803 int CompGlyph;
804 CompGlyph = GET_BE_WORD(lig->Component[l]);
805 if (CompGlyph != glyphs[CompIndex])
806 break;
807 CompIndex += write_dir;
809 if (l == CompCount)
811 int replaceIdx = glyph_index;
812 if (write_dir < 0)
813 replaceIdx = glyph_index - CompCount;
815 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
816 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
817 TRACE("0x%x\n",glyphs[replaceIdx]);
818 if (CompCount > 0)
820 int j;
821 for (j = replaceIdx + 1; j < *glyph_count; j++)
822 glyphs[j] =glyphs[j+CompCount];
823 *glyph_count = *glyph_count - CompCount;
825 return replaceIdx + 1;
830 return GSUB_E_NOGLYPH;
833 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
835 int j;
836 BOOL done = FALSE;
838 TRACE("Chaining Contextual Substitution Subtable\n");
839 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
841 const GSUB_ChainContextSubstFormat1 *ccsf1;
842 int offset;
843 int dirLookahead = write_dir;
844 int dirBacktrack = -1 * write_dir;
846 offset = GET_BE_WORD(look->SubTable[j]);
847 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
848 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
850 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
851 continue;
853 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
855 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
856 continue;
858 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
860 int k;
861 int indexGlyphs;
862 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
863 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
864 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
865 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
866 int newIndex = glyph_index;
868 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
870 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
872 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
874 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
875 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
876 break;
878 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
879 continue;
880 TRACE("Matched Backtrack\n");
882 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
884 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
885 for (k = 0; k < indexGlyphs; k++)
887 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
888 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
889 break;
891 if (k != indexGlyphs)
892 continue;
893 TRACE("Matched IndexGlyphs\n");
895 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
897 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
899 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
900 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
901 break;
903 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
904 continue;
905 TRACE("Matched LookAhead\n");
907 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
909 if (GET_BE_WORD(ccsf3_4->SubstCount))
911 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
913 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
914 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
916 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
917 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
918 if (newIndex == -1)
920 ERR("Chain failed to generate a glyph\n");
921 continue;
924 return newIndex;
926 else return GSUB_E_NOGLYPH;
929 return -1;
932 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
934 int offset;
935 const GSUB_LookupTable *look;
937 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
938 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
939 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
940 switch(GET_BE_WORD(look->LookupType))
942 case 1:
943 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
944 case 3:
945 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
946 case 4:
947 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
948 case 6:
949 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
950 default:
951 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
953 return GSUB_E_NOGLYPH;
956 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
958 int i;
959 int out_index = GSUB_E_NOGLYPH;
960 const GSUB_LookupList *lookup;
962 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
964 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
965 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
967 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
968 if (out_index != GSUB_E_NOGLYPH)
969 break;
971 if (out_index == GSUB_E_NOGLYPH)
972 TRACE("lookups found no glyphs\n");
973 else
975 int out2;
976 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
977 if (out2!=GSUB_E_NOGLYPH)
978 out_index = out2;
980 return out_index;
983 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
985 UINT charset;
987 if (psc->userScript != 0)
989 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
990 return ShapingData[psa->eScript].newOtTag;
991 else
992 return (char*)&psc->userScript;
995 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
996 return ShapingData[psa->eScript].newOtTag;
998 if (ShapingData[psa->eScript].otTag[0] != 0)
999 return ShapingData[psa->eScript].otTag;
1002 * fall back to the font charset
1004 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1005 switch (charset)
1007 case ANSI_CHARSET: return "latn";
1008 case BALTIC_CHARSET: return "latn"; /* ?? */
1009 case CHINESEBIG5_CHARSET: return "hani";
1010 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1011 case GB2312_CHARSET: return "hani";
1012 case GREEK_CHARSET: return "grek";
1013 case HANGUL_CHARSET: return "hang";
1014 case RUSSIAN_CHARSET: return "cyrl";
1015 case SHIFTJIS_CHARSET: return "kana";
1016 case TURKISH_CHARSET: return "latn"; /* ?? */
1017 case VIETNAMESE_CHARSET: return "latn";
1018 case JOHAB_CHARSET: return "latn"; /* ?? */
1019 case ARABIC_CHARSET: return "arab";
1020 case HEBREW_CHARSET: return "hebr";
1021 case THAI_CHARSET: return "thai";
1022 default: return "latn";
1026 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1028 const GSUB_Feature *feature;
1029 int i;
1031 for (i = 0; i < psc->feature_count; i++)
1032 if (strncmp(psc->features[i].tag,feat,4)==0)
1033 return psc->features[i].feature;
1035 feature = NULL;
1037 if (psc->GSUB_Table)
1039 const GSUB_Script *script;
1040 const GSUB_LangSys *language;
1041 int attempt = 2;
1045 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1046 attempt--;
1047 if (script)
1049 if (psc->userLang != 0)
1050 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1051 else
1052 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1053 if (language)
1054 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1056 } while(attempt && !feature);
1058 /* try in the default (latin) table */
1059 if (!feature)
1061 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1062 if (script)
1064 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1065 if (language)
1066 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1071 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1073 psc->feature_count++;
1075 if (psc->features)
1076 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1077 else
1078 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1080 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1081 psc->features[psc->feature_count - 1].feature = feature;
1082 return feature;
1085 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)
1087 const GSUB_Feature *feature;
1089 feature = load_GSUB_feature(hdc, psa, psc, feat);
1090 if (!feature)
1091 return GSUB_E_NOFEATURE;
1093 TRACE("applying feature %s\n",feat);
1094 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1097 static VOID *load_gsub_table(HDC hdc)
1099 VOID* GSUB_Table = NULL;
1100 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1101 if (length != GDI_ERROR)
1103 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1104 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1105 TRACE("Loaded GSUB table of %i bytes\n",length);
1107 return GSUB_Table;
1110 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)
1112 WORD *glyphs;
1113 INT glyph_count = count;
1114 INT rc;
1116 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1117 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1118 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1119 if (rc > GSUB_E_NOGLYPH)
1120 rc = count - glyph_count;
1121 else
1122 rc = 0;
1124 HeapFree(GetProcessHeap(),0,glyphs);
1125 return rc;
1128 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1130 int offset;
1131 WORD class = 0;
1132 const GDEF_ClassDefFormat1 *cf1;
1134 if (!header)
1135 return 0;
1137 offset = GET_BE_WORD(header->GlyphClassDef);
1138 if (!offset)
1139 return 0;
1141 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1142 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1144 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1146 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1147 if (index < GET_BE_WORD(cf1->GlyphCount))
1148 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1151 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1153 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1154 int i, top;
1155 top = GET_BE_WORD(cf2->ClassRangeCount);
1156 for (i = 0; i < top; i++)
1158 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1159 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1161 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1162 break;
1166 else
1167 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1169 return class;
1172 static VOID *load_gdef_table(HDC hdc)
1174 VOID* GDEF_Table = NULL;
1175 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1176 if (length != GDI_ERROR)
1178 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1179 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1180 TRACE("Loaded GDEF table of %i bytes\n",length);
1182 return GDEF_Table;
1185 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1187 int i;
1189 if (!psc->GDEF_Table)
1190 psc->GDEF_Table = load_gdef_table(hdc);
1192 for (i = 0; i < cGlyphs; i++)
1194 WORD class;
1196 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1198 switch (class)
1200 case 0:
1201 case BaseGlyph:
1202 pGlyphProp[i].sva.fClusterStart = 1;
1203 pGlyphProp[i].sva.fDiacritic = 0;
1204 pGlyphProp[i].sva.fZeroWidth = 0;
1205 break;
1206 case LigatureGlyph:
1207 pGlyphProp[i].sva.fClusterStart = 1;
1208 pGlyphProp[i].sva.fDiacritic = 0;
1209 pGlyphProp[i].sva.fZeroWidth = 0;
1210 break;
1211 case MarkGlyph:
1212 pGlyphProp[i].sva.fClusterStart = 0;
1213 pGlyphProp[i].sva.fDiacritic = 1;
1214 pGlyphProp[i].sva.fZeroWidth = 1;
1215 break;
1216 case ComponentGlyph:
1217 pGlyphProp[i].sva.fClusterStart = 0;
1218 pGlyphProp[i].sva.fDiacritic = 0;
1219 pGlyphProp[i].sva.fZeroWidth = 0;
1220 break;
1221 default:
1222 ERR("Unknown glyph class %i\n",class);
1223 pGlyphProp[i].sva.fClusterStart = 1;
1224 pGlyphProp[i].sva.fDiacritic = 0;
1225 pGlyphProp[i].sva.fZeroWidth = 0;
1230 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1232 int i;
1234 for (i = 0; i < cGlyphs; i++)
1236 if (!pGlyphProp[i].sva.fClusterStart)
1238 int j;
1239 for (j = 0; j < cChars; j++)
1241 if (pwLogClust[j] == i)
1243 int k = j;
1244 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1245 k-=1;
1246 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1247 pwLogClust[j] = pwLogClust[k];
1254 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1256 if (changeCount == 0)
1257 return;
1258 else
1260 int i;
1261 int target_glyph = nextIndex - 1;
1262 int target_index = -1;
1263 int replacing_glyph = -1;
1264 int changed = 0;
1266 if (write_dir > 0)
1267 for (i = 0; i < chars; i++)
1269 if (pwLogClust[i] == target_glyph)
1271 target_index = i;
1272 break;
1275 else
1276 for (i = chars - 1; i >= 0; i--)
1278 if (pwLogClust[i] == target_glyph)
1280 target_index = i;
1281 break;
1284 if (target_index == -1)
1286 ERR("Unable to find target glyph\n");
1287 return;
1290 if (changeCount < 0)
1292 /* merge glyphs */
1293 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1295 if (pwLogClust[i] == target_glyph)
1296 continue;
1297 if(pwLogClust[i] == replacing_glyph)
1298 pwLogClust[i] = target_glyph;
1299 else
1301 changed--;
1302 if (changed >= changeCount)
1304 replacing_glyph = pwLogClust[i];
1305 pwLogClust[i] = target_glyph;
1307 else
1308 break;
1313 /* renumber trailing indexes*/
1314 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1316 if (pwLogClust[i] != target_glyph)
1317 pwLogClust[i] += changeCount;
1322 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 )
1324 int i;
1326 if (psc->GSUB_Table)
1328 const GSUB_Feature *feature;
1330 feature = load_GSUB_feature(hdc, psa, psc, feat);
1331 if (!feature)
1332 return GSUB_E_NOFEATURE;
1334 i = 0;
1335 TRACE("applying feature %s\n",debugstr_an(feat,4));
1336 while(i < *pcGlyphs)
1338 INT nextIndex;
1339 INT prevCount = *pcGlyphs;
1340 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1341 if (nextIndex > GSUB_E_NOGLYPH)
1343 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1344 i = nextIndex;
1346 else
1347 i++;
1349 return *pcGlyphs;
1351 return GSUB_E_NOFEATURE;
1354 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1356 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1359 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1361 if (i + delta < 0)
1362 return 0;
1363 if ( i+ delta >= cchLen)
1364 return 0;
1366 i += delta;
1368 return chars[i];
1371 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1373 if (i + delta < 0)
1375 if (psa->fLinkBefore)
1376 return jtR;
1377 else
1378 return jtU;
1380 if ( i+ delta >= cchLen)
1382 if (psa->fLinkAfter)
1383 return jtL;
1384 else
1385 return jtU;
1388 i += delta;
1390 if (context_type[i] == jtT)
1391 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1392 else
1393 return context_type[i];
1396 static inline BOOL right_join_causing(CHAR joining_type)
1398 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1401 static inline BOOL left_join_causing(CHAR joining_type)
1403 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1406 static inline BOOL word_break_causing(WCHAR chr)
1408 /* we are working within a string of characters already guareented to
1409 be within one script, Syriac, so we do not worry about any characers
1410 other than the space character outside of that range */
1411 return (chr == 0 || chr == 0x20 );
1415 * ContextualShape_Arabic
1417 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1419 CHAR *context_type;
1420 INT *context_shape;
1421 INT dirR, dirL;
1422 int i;
1424 if (*pcGlyphs != cChars)
1426 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1427 return;
1430 if (!psa->fLogicalOrder && psa->fRTL)
1432 dirR = 1;
1433 dirL = -1;
1435 else
1437 dirR = -1;
1438 dirL = 1;
1441 if (!psc->GSUB_Table)
1442 psc->GSUB_Table = load_gsub_table(hdc);
1444 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1445 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1447 for (i = 0; i < cChars; i++)
1448 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1450 for (i = 0; i < cChars; i++)
1452 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1453 context_shape[i] = Xr;
1454 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1455 context_shape[i] = Xl;
1456 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)))
1457 context_shape[i] = Xm;
1458 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1459 context_shape[i] = Xr;
1460 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1461 context_shape[i] = Xl;
1462 else
1463 context_shape[i] = Xn;
1466 /* Contextual Shaping */
1467 i = 0;
1468 while(i < *pcGlyphs)
1470 BOOL shaped = FALSE;
1472 if (psc->GSUB_Table)
1474 INT nextIndex;
1475 INT prevCount = *pcGlyphs;
1476 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1477 if (nextIndex > GSUB_E_NOGLYPH)
1479 i = nextIndex;
1480 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1482 shaped = (nextIndex > GSUB_E_NOGLYPH);
1485 if (!shaped)
1487 WORD newGlyph = pwOutGlyphs[i];
1488 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1490 /* fall back to presentation form B */
1491 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1492 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1493 pwOutGlyphs[i] = newGlyph;
1495 i++;
1499 HeapFree(GetProcessHeap(),0,context_shape);
1500 HeapFree(GetProcessHeap(),0,context_type);
1504 * ContextualShape_Syriac
1507 #define ALAPH 0x710
1508 #define DALATH 0x715
1509 #define RISH 0x72A
1511 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1513 CHAR *context_type;
1514 INT *context_shape;
1515 INT dirR, dirL;
1516 int i;
1518 if (*pcGlyphs != cChars)
1520 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1521 return;
1524 if (!psa->fLogicalOrder && psa->fRTL)
1526 dirR = 1;
1527 dirL = -1;
1529 else
1531 dirR = -1;
1532 dirL = 1;
1535 if (!psc->GSUB_Table)
1536 psc->GSUB_Table = load_gsub_table(hdc);
1538 if (!psc->GSUB_Table)
1539 return;
1541 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1542 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1544 for (i = 0; i < cChars; i++)
1545 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1547 for (i = 0; i < cChars; i++)
1549 if (pwcChars[i] == ALAPH)
1551 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1553 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1554 context_shape[i] = Afj;
1555 else if ( rchar != DALATH && rchar != RISH &&
1556 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1557 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1558 context_shape[i] = Afn;
1559 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1560 context_shape[i] = Afx;
1561 else
1562 context_shape[i] = Xn;
1564 else if (context_type[i] == jtR &&
1565 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1566 context_shape[i] = Xr;
1567 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1568 context_shape[i] = Xl;
1569 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)))
1570 context_shape[i] = Xm;
1571 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1572 context_shape[i] = Xr;
1573 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1574 context_shape[i] = Xl;
1575 else
1576 context_shape[i] = Xn;
1579 /* Contextual Shaping */
1580 i = 0;
1581 while(i < *pcGlyphs)
1583 INT nextIndex;
1584 INT prevCount = *pcGlyphs;
1585 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1586 if (nextIndex > GSUB_E_NOGLYPH)
1588 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1589 i = nextIndex;
1591 else
1592 i++;
1595 HeapFree(GetProcessHeap(),0,context_shape);
1596 HeapFree(GetProcessHeap(),0,context_type);
1600 * ContextualShape_Phags_pa
1603 #define phags_pa_CANDRABINDU 0xA873
1604 #define phags_pa_START 0xA840
1605 #define phags_pa_END 0xA87F
1607 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1609 INT *context_shape;
1610 INT dirR, dirL;
1611 int i;
1613 if (*pcGlyphs != cChars)
1615 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1616 return;
1619 if (!psa->fLogicalOrder && psa->fRTL)
1621 dirR = 1;
1622 dirL = -1;
1624 else
1626 dirR = -1;
1627 dirL = 1;
1630 if (!psc->GSUB_Table)
1631 psc->GSUB_Table = load_gsub_table(hdc);
1633 if (!psc->GSUB_Table)
1634 return;
1636 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1638 for (i = 0; i < cChars; i++)
1640 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1642 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1643 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1644 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1645 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1647 if (jrchar && jlchar)
1648 context_shape[i] = Xm;
1649 else if (jrchar)
1650 context_shape[i] = Xr;
1651 else if (jlchar)
1652 context_shape[i] = Xl;
1653 else
1654 context_shape[i] = Xn;
1656 else
1657 context_shape[i] = -1;
1660 /* Contextual Shaping */
1661 i = 0;
1662 while(i < *pcGlyphs)
1664 if (context_shape[i] >= 0)
1666 INT nextIndex;
1667 INT prevCount = *pcGlyphs;
1668 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1669 if (nextIndex > GSUB_E_NOGLYPH)
1671 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1672 i = nextIndex;
1674 else
1675 i++;
1677 else
1678 i++;
1681 HeapFree(GetProcessHeap(),0,context_shape);
1684 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1686 int i;
1688 /* Replace */
1689 pwOutChars[cWalk] = replacements[0];
1690 cWalk=cWalk+1;
1692 /* Insert */
1693 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1695 int j;
1696 for (j = *pcChars; j > cWalk; j--)
1697 pwOutChars[j] = pwOutChars[j-1];
1698 *pcChars= *pcChars+1;
1699 pwOutChars[cWalk] = replacements[i];
1700 cWalk = cWalk+1;
1704 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1706 int i;
1707 int cWalk;
1709 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1711 for (i = 0; vowels[i].base != 0x0; i++)
1713 if (pwOutChars[cWalk] == vowels[i].base)
1715 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1716 if (vowels[i].parts[1]) cWalk++;
1717 if (vowels[i].parts[2]) cWalk++;
1718 break;
1724 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1726 int i;
1727 int cWalk;
1729 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1731 for (i = 0; consonants[i].output!= 0x0; i++)
1733 int j;
1734 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1735 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1736 break;
1738 if (consonants[i].parts[j]==0x0) /* matched all */
1740 int k;
1741 j--;
1742 pwOutChars[cWalk] = consonants[i].output;
1743 for(k = cWalk+1; k < *pcChars - j; k++)
1744 pwOutChars[k] = pwOutChars[k+j];
1745 *pcChars = *pcChars - j;
1746 break;
1749 cWalk++;
1753 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1755 if (s->ralf >= 0)
1757 int j;
1758 WORD Ra = pwChar[s->start];
1759 WORD H = pwChar[s->start+1];
1761 TRACE("Doing reorder of Ra to %i\n",s->base);
1762 for (j = s->start; j < s->base-1; j++)
1763 pwChar[j] = pwChar[j+2];
1764 pwChar[s->base-1] = Ra;
1765 pwChar[s->base] = H;
1767 s->ralf = s->base-1;
1768 s->base -= 2;
1772 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1774 if (s->ralf >= 0)
1776 int j,loc;
1777 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1778 WORD Ra = pwChar[s->start];
1779 WORD H = pwChar[s->start+1];
1780 for (loc = s->end; loc > stop; loc--)
1781 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1782 break;
1784 TRACE("Doing reorder of Ra to %i\n",loc);
1785 for (j = s->start; j < loc-1; j++)
1786 pwChar[j] = pwChar[j+2];
1787 pwChar[loc-1] = Ra;
1788 pwChar[loc] = H;
1790 s->ralf = loc-1;
1791 s->base -= 2;
1792 if (s->blwf >= 0) s->blwf -= 2;
1793 if (s->pref >= 0) s->pref -= 2;
1797 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1799 if (s->ralf >= 0)
1801 int j;
1802 WORD Ra = pwChar[s->start];
1803 WORD H = pwChar[s->start+1];
1805 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1806 for (j = s->start; j < s->end-1; j++)
1807 pwChar[j] = pwChar[j+2];
1808 pwChar[s->end-1] = Ra;
1809 pwChar[s->end] = H;
1811 s->ralf = s->end-1;
1812 s->base -= 2;
1813 if (s->blwf >= 0) s->blwf -= 2;
1814 if (s->pref >= 0) s->pref -= 2;
1818 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1820 int i;
1822 /* reorder Matras */
1823 if (s->end > s->base)
1825 for (i = 1; i <= s->end-s->base; i++)
1827 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1829 int j;
1830 WCHAR c = pwChar[s->base+i];
1831 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1832 for (j = s->base+i; j > s->base; j--)
1833 pwChar[j] = pwChar[j-1];
1834 pwChar[s->base] = c;
1836 if (s->ralf >= s->base) s->ralf++;
1837 if (s->blwf >= s->base) s->blwf++;
1838 if (s->pref >= s->base) s->pref++;
1839 s->base ++;
1845 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1847 int i;
1849 /* reorder Matras */
1850 if (s->end > s->base)
1852 for (i = 1; i <= s->end-s->base; i++)
1854 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1856 int j;
1857 WCHAR c = pwChar[s->base+i];
1858 TRACE("Doing reorder of %x to %i\n",c,s->start);
1859 for (j = s->base+i; j > s->start; j--)
1860 pwChar[j] = pwChar[j-1];
1861 pwChar[s->start] = c;
1863 if (s->ralf >= 0) s->ralf++;
1864 if (s->blwf >= 0) s->blwf++;
1865 if (s->pref >= 0) s->pref++;
1866 s->base ++;
1872 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1874 if (s->blwf >= 0 && g->blwf > g->base)
1876 int j,loc;
1877 int g_offset;
1878 for (loc = s->end; loc > s->blwf; loc--)
1879 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1880 break;
1882 g_offset = (loc - s->blwf) - 1;
1884 if (loc != s->blwf)
1886 WORD blwf = glyphs[g->blwf];
1887 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1888 /* do not care about the pwChar array anymore, just the glyphs */
1889 for (j = 0; j < g_offset; j++)
1890 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1891 glyphs[g->blwf + g_offset] = blwf;
1896 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1898 int i;
1900 /* reorder previously moved Matras to correct position*/
1901 for (i = s->start; i < s->base; i++)
1903 if (lexical(pwChar[i]) == lex_Matra_pre)
1905 int j;
1906 int g_start = g->start + i - s->start;
1907 if (g_start < g->base -1 )
1909 WCHAR og = glyphs[g_start];
1910 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1911 for (j = g_start; j < g->base-1; j++)
1912 glyphs[j] = glyphs[j+1];
1913 glyphs[g->base-1] = og;
1919 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1921 if (s->pref >= 0 && g->pref > g->base)
1923 int j;
1924 WCHAR og = glyphs[g->pref];
1925 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1926 for (j = g->pref; j > g->base; j--)
1927 glyphs[j] = glyphs[j-1];
1928 glyphs[g->base] = og;
1932 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1934 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1935 if (s->start == s->base && s->base == s->end) return;
1936 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1938 Reorder_Ra_follows_base(pwChar, s, lexical);
1939 Reorder_Matra_precede_base(pwChar, s, lexical);
1942 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1944 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1945 if (s->start == s->base && s->base == s->end) return;
1946 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1948 Reorder_Ra_follows_matra(pwChar, s, lexical);
1949 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1952 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1954 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1955 if (s->start == s->base && s->base == s->end) return;
1956 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1958 Reorder_Ra_follows_base(pwChar, s, lexical);
1959 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1962 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1964 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1965 if (s->start == s->base && s->base == s->end) return;
1966 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1968 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1969 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1972 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1974 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1975 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1976 if (s->start == s->base && s->base == s->end) return;
1977 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1979 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1982 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1984 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1985 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1986 if (s->start == s->base && s->base == s->end) return;
1987 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1989 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1990 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1994 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1996 if (shift == 0)
1997 return;
1999 if (glyph_index->start > index)
2000 glyph_index->start += shift;
2001 if (glyph_index->base > index)
2002 glyph_index->base+= shift;
2003 if (glyph_index->end > index)
2004 glyph_index->end+= shift;
2005 if (glyph_index->ralf > index)
2006 glyph_index->ralf+= shift;
2007 if (glyph_index->blwf > index)
2008 glyph_index->blwf+= shift;
2009 if (glyph_index->pref > index)
2010 glyph_index->pref+= shift;
2013 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, const GSUB_Feature *feature )
2015 int index = glyph_index->start;
2017 if (!feature)
2018 return;
2020 while(index <= glyph_index->end)
2022 INT nextIndex;
2023 INT prevCount = *pcGlyphs;
2024 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2025 if (nextIndex > GSUB_E_NOGLYPH)
2027 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2028 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2029 index = nextIndex;
2031 else
2032 index++;
2036 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2038 int i = 0;
2039 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)))))
2040 i++;
2041 if (index + i <= end-1)
2042 return index + i;
2043 else
2044 return -1;
2047 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)
2049 INT index, nextIndex;
2050 INT count,g_offset;
2051 INT prevCount = *pcGlyphs;
2053 count = syllable->base - syllable->start;
2055 g_offset = 0;
2056 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2057 while (index >= 0 && index < (glyph_index->base - glyph_index->start))
2059 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2060 if (nextIndex > GSUB_E_NOGLYPH)
2062 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2063 g_offset += (*pcGlyphs - prevCount);
2064 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start, g_offset);
2067 index+=2;
2068 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2072 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)
2074 INT nextIndex;
2075 INT prevCount = *pcGlyphs;
2077 if (syllable->ralf >= 0)
2079 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2080 if (nextIndex > GSUB_E_NOGLYPH)
2082 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2083 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2088 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2090 int i = 0;
2091 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2092 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2093 is_consonant(lexical(pwChars[index+i+1])))))
2094 i++;
2095 if (index + i <= end-1)
2096 return index+i;
2097 else
2098 return -1;
2101 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)
2103 INT index, nextIndex;
2104 INT count, g_offset=0;
2105 INT ralf = syllable->ralf;
2107 count = syllable->end - syllable->base;
2109 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2111 while (index >= 0)
2113 INT prevCount = *pcGlyphs;
2114 if (ralf >=0 && ralf < index)
2116 g_offset--;
2117 ralf = -1;
2120 if (!modern)
2122 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2123 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2124 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2127 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2128 if (nextIndex > GSUB_E_NOGLYPH)
2130 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2131 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2132 g_offset += (*pcGlyphs - prevCount);
2134 else if (!modern)
2136 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2137 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2138 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2141 index+=2;
2142 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2146 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)
2148 int c;
2149 int overall_shift = 0;
2150 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2151 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2152 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2153 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2154 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2155 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2156 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2157 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2158 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2159 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2160 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2161 IndicSyllable glyph_indexs;
2163 for (c = 0; c < syllable_count; c++)
2165 int old_end;
2166 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2167 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2168 old_end = glyph_indexs.end;
2170 if (locl)
2172 TRACE("applying feature locl\n");
2173 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2175 if (nukt)
2177 TRACE("applying feature nukt\n");
2178 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2180 if (akhn)
2182 TRACE("applying feature akhn\n");
2183 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2186 if (rphf)
2187 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2188 if (rkrf)
2190 TRACE("applying feature rkrf\n");
2191 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2193 if (pref)
2194 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2195 if (blwf)
2197 if (!modern)
2198 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2200 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2203 if (half)
2204 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2205 if (pstf)
2207 TRACE("applying feature pstf\n");
2208 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2210 if (vatu)
2212 TRACE("applying feature vatu\n");
2213 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2215 if (cjct)
2217 TRACE("applying feature cjct\n");
2218 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2221 if (second_reorder)
2222 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2224 overall_shift += glyph_indexs.end - old_end;
2228 static int sinhala_lex(WCHAR c)
2230 switch (c)
2232 case 0x0DCA: return lex_Halant;
2233 case 0x0DCF:
2234 case 0x0DDF:
2235 case 0x0DD8: return lex_Matra_post;
2236 case 0x0DD9:
2237 case 0x0DDB: return lex_Matra_pre;
2238 case 0x0DDA:
2239 case 0x0DDC: return lex_Matra_post;
2240 case 0x200D: return lex_ZWJ;
2241 case 0x200C: return lex_ZWNJ;
2242 case 0x00A0: return lex_NBSP;
2243 default:
2244 if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
2245 else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
2246 else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
2247 else if (c>=0x0DD0 && c <=0x0DD1) return lex_Matra_post;
2248 else if (c>=0x0DD2 && c <=0x0DD3) return lex_Matra_above;
2249 else if (c>=0x0DD4 && c <=0x0DD6) return lex_Matra_below;
2250 else if (c>=0x0DDD && c <=0x0DDE) return lex_Matra_post;
2251 else if (c>=0x0DF2 && c <=0x0DF3) return lex_Matra_post;
2252 else return lex_Generic;
2256 static const VowelComponents Sinhala_vowels[] = {
2257 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2258 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2259 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2260 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2261 {0x0000, {0x0000,0x0000,0x0}}};
2263 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2265 int cCount = cChars;
2266 int i;
2267 WCHAR *input;
2268 IndicSyllable *syllables = NULL;
2269 int syllable_count = 0;
2271 if (*pcGlyphs != cChars)
2273 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2274 return;
2277 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2279 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2281 /* Step 1: Decompose multi part vowels */
2282 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels);
2284 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2286 /* Step 2: Reorder within Syllables */
2287 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2288 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2290 /* Step 3: Strip dangling joiners */
2291 for (i = 0; i < cCount; i++)
2293 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2294 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2295 input[i] = 0x0020;
2298 /* Step 4: Base Form application to syllables */
2299 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2300 *pcGlyphs = cCount;
2301 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2303 HeapFree(GetProcessHeap(),0,input);
2304 HeapFree(GetProcessHeap(),0,syllables);
2307 static int devanagari_lex(WCHAR c)
2309 switch (c)
2311 case 0x0951:
2312 case 0x0952:
2313 case 0x0903: return lex_Modifier;
2314 case 0x0930: return lex_Ra;
2315 case 0x093C: return lex_Nukta;
2316 case 0x0940:
2317 case 0x093E: return lex_Matra_post;
2318 case 0x093F: return lex_Matra_pre;
2319 case 0x094D: return lex_Halant;
2320 case 0x0972: return lex_Vowel;
2321 case 0x200C: return lex_ZWNJ;
2322 case 0x200D: return lex_ZWJ;
2323 default:
2324 if (c>=0x0901 && c<=0x0902) return lex_Matra_above;
2325 else if (c>=0x0904 && c<=0x0914) return lex_Vowel;
2326 else if (c>=0x0915 && c<=0x0939) return lex_Consonant;
2327 else if (c>=0x0941 && c<=0x0944) return lex_Matra_below;
2328 else if (c>=0x0945 && c<=0x0948) return lex_Matra_above;
2329 else if (c>=0x0949 && c<=0x094C) return lex_Matra_post;
2330 else if (c>=0x0953 && c<=0x0954) return lex_Modifier;
2331 else if (c>=0x0958 && c<=0x095F) return lex_Consonant;
2332 else if (c>=0x0960 && c<=0x0961) return lex_Vowel;
2333 else if (c>=0x0962 && c<=0x0963) return lex_Matra_below;
2334 else if (c>=0x097B && c<=0x097C) return lex_Consonant;
2335 else if (c>=0x097E && c<=0x097F) return lex_Consonant;
2336 else return lex_Generic;
2340 static const ConsonantComponents Devanagari_consonants[] ={
2341 {{0x0928, 0x093C, 0x00000}, 0x0929},
2342 {{0x0930, 0x093C, 0x00000}, 0x0931},
2343 {{0x0933, 0x093C, 0x00000}, 0x0934},
2344 {{0x0915, 0x093C, 0x00000}, 0x0958},
2345 {{0x0916, 0x093C, 0x00000}, 0x0959},
2346 {{0x0917, 0x093C, 0x00000}, 0x095A},
2347 {{0x091C, 0x093C, 0x00000}, 0x095B},
2348 {{0x0921, 0x093C, 0x00000}, 0x095C},
2349 {{0x0922, 0x093C, 0x00000}, 0x095D},
2350 {{0x092B, 0x093C, 0x00000}, 0x095E},
2351 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2353 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2355 int cCount = cChars;
2356 WCHAR *input;
2357 IndicSyllable *syllables = NULL;
2358 int syllable_count = 0;
2359 BOOL modern = get_GSUB_Indic2(psa, psc);
2361 if (*pcGlyphs != cChars)
2363 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2364 return;
2367 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2368 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2370 /* Step 1: Compose Consonant and Nukta */
2371 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2372 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2374 /* Step 2: Reorder within Syllables */
2375 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2376 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2377 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2378 *pcGlyphs = cCount;
2380 /* Step 3: Base Form application to syllables */
2381 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2383 HeapFree(GetProcessHeap(),0,input);
2384 HeapFree(GetProcessHeap(),0,syllables);
2387 static int bengali_lex(WCHAR c)
2389 switch (c)
2391 case 0x0981: return lex_Modifier;
2392 case 0x09AC:
2393 case 0x09AF:
2394 case 0x09CE: return lex_Consonant;
2395 case 0x09B0: return lex_Ra;
2396 case 0x09BC: return lex_Nukta;
2397 case 0x09BF: return lex_Matra_pre;
2398 case 0x09D7:
2399 case 0x09BE:
2400 case 0x09C0: return lex_Matra_post;
2401 case 0x09CD: return lex_Halant;
2402 case 0x200C: return lex_ZWNJ;
2403 case 0x200D: return lex_ZWJ;
2404 default:
2405 if (c>=0x0982 && c<=0x0983) return lex_Matra_post;
2406 else if (c>=0x0985 && c<=0x0994) return lex_Vowel;
2407 else if (c>=0x0995 && c<=0x09B9) return lex_Consonant;
2408 else if (c>=0x09C1 && c<=0x09C4) return lex_Matra_below;
2409 else if (c>=0x09C7 && c<=0x09C8) return lex_Matra_pre;
2410 else if (c>=0x09DC && c<=0x09DF) return lex_Consonant;
2411 else if (c>=0x09E0 && c<=0x09E1) return lex_Vowel;
2412 else if (c>=0x09E2 && c<=0x09E3) return lex_Matra_below;
2413 else if (c>=0x09F0 && c<=0x09F1) return lex_Consonant;
2414 else return lex_Generic;
2418 static const VowelComponents Bengali_vowels[] = {
2419 {0x09CB, {0x09C7,0x09BE,0x0000}},
2420 {0x09CC, {0x09C7,0x09D7,0x0000}},
2421 {0x0000, {0x0000,0x0000,0x0000}}};
2423 static const ConsonantComponents Bengali_consonants[] = {
2424 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2425 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2426 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2427 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2428 {{0x0000,0x0000,0x0000}, 0x0000}};
2430 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2432 int cCount = cChars;
2433 WCHAR *input;
2434 IndicSyllable *syllables = NULL;
2435 int syllable_count = 0;
2436 BOOL modern = get_GSUB_Indic2(psa, psc);
2438 if (*pcGlyphs != cChars)
2440 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2441 return;
2444 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2445 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2447 /* Step 1: Decompose Vowels and Compose Consonents */
2448 DecomposeVowels(hdc, input, &cCount, Bengali_vowels);
2449 ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2450 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2452 /* Step 2: Reorder within Syllables */
2453 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2454 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2455 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2456 *pcGlyphs = cCount;
2458 /* Step 3: Initial form is only applied to the beginning of words */
2459 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2461 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2463 int index = cCount;
2464 int gCount = 1;
2465 if (index > 0) index++;
2467 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2471 /* Step 4: Base Form application to syllables */
2472 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2474 HeapFree(GetProcessHeap(),0,input);
2475 HeapFree(GetProcessHeap(),0,syllables);
2478 static int gurmukhi_lex(WCHAR c)
2480 switch (c)
2482 case 0x0A30:
2483 case 0x0A35:
2484 case 0x0A39:
2485 case 0x0A2f: return lex_Consonant;
2486 case 0x0A3C: return lex_Nukta;
2487 case 0x0A3F: return lex_Matra_pre;
2488 case 0x0A03:
2489 case 0x0A3E:
2490 case 0x0A40: return lex_Matra_post;
2491 case 0x0A4D: return lex_Halant;
2492 case 0x0A70:
2493 case 0x0A71: return lex_Modifier;
2494 case 0x200C: return lex_ZWNJ;
2495 case 0x200D: return lex_ZWJ;
2496 default:
2497 if (c>=0x0A01 && c<=0x0A02) return lex_Modifier;
2498 else if (c>=0x0A05 && c<=0x0A14) return lex_Vowel;
2499 else if (c>=0x0A15 && c<=0x0A38) return lex_Consonant;
2500 else if (c>=0x0A41 && c<=0x0A42) return lex_Matra_below;
2501 else if (c>=0x0A47 && c<=0x0A4C) return lex_Matra_above;
2502 else if (c>=0x0A59 && c<=0x0A5E) return lex_Consonant;
2503 else return lex_Generic;
2507 static const ConsonantComponents Gurmukhi_consonants[] = {
2508 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2509 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2510 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2511 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2512 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2513 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2514 {{0x0000,0x0000,0x0000}, 0x0000}};
2516 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2518 int cCount = cChars;
2519 WCHAR *input;
2520 IndicSyllable *syllables = NULL;
2521 int syllable_count = 0;
2522 BOOL modern = get_GSUB_Indic2(psa, psc);
2524 if (*pcGlyphs != cChars)
2526 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2527 return;
2530 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2531 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2533 /* Step 1: Compose Consonents */
2534 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2535 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2537 /* Step 2: Reorder within Syllables */
2538 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2539 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2540 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2541 *pcGlyphs = cCount;
2543 /* Step 3: Base Form application to syllables */
2544 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2546 HeapFree(GetProcessHeap(),0,input);
2547 HeapFree(GetProcessHeap(),0,syllables);
2550 static int gujarati_lex(WCHAR c)
2552 switch (c)
2554 case 0x0A83: return lex_Modifier;
2555 case 0x0AB0: return lex_Ra;
2556 case 0x0ABC: return lex_Nukta;
2557 case 0x0ABF: return lex_Matra_pre;
2558 case 0x0ABE:
2559 case 0x0AC0: return lex_Matra_post;
2560 case 0x0ACD: return lex_Halant;
2561 case 0x200C: return lex_ZWNJ;
2562 case 0x200D: return lex_ZWJ;
2563 default:
2564 if (c>=0x0A81 && c<=0x0A82) return lex_Modifier;
2565 else if (c>=0x0A85 && c<=0x0A94) return lex_Vowel;
2566 else if (c>=0x0A95 && c<=0x0AB9) return lex_Consonant;
2567 else if (c>=0x0AC1 && c<=0x0AC4) return lex_Matra_below;
2568 else if (c>=0x0AC5 && c<=0x0AC8) return lex_Matra_above;
2569 else if (c>=0x0AC9 && c<=0x0ACC) return lex_Matra_post;
2570 else if (c>=0x0AE0 && c<=0x0AE1) return lex_Vowel;
2571 else if (c>=0x0AE2 && c<=0x0AE3) return lex_Matra_below;
2572 else return lex_Generic;
2576 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2578 int cCount = cChars;
2579 WCHAR *input;
2580 IndicSyllable *syllables = NULL;
2581 int syllable_count = 0;
2582 BOOL modern = get_GSUB_Indic2(psa, psc);
2584 if (*pcGlyphs != cChars)
2586 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2587 return;
2590 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2591 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2593 /* Step 1: Reorder within Syllables */
2594 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2595 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2596 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2597 *pcGlyphs = cCount;
2599 /* Step 2: Base Form application to syllables */
2600 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2602 HeapFree(GetProcessHeap(),0,input);
2603 HeapFree(GetProcessHeap(),0,syllables);
2606 static int oriya_lex(WCHAR c)
2608 switch (c)
2610 case 0x0B24:
2611 case 0x0B28:
2612 case 0x0B2F:
2613 case 0x0B5F:
2614 case 0x0B71:
2615 case 0x0B33: return lex_Consonant;
2616 case 0x0B30: return lex_Ra;
2617 case 0x0B3C: return lex_Nukta;
2618 case 0x0B3F:
2619 case 0x0B56: return lex_Matra_above;
2620 case 0x0B3E:
2621 case 0x0B57:
2622 case 0x0B40: return lex_Matra_post;
2623 case 0x0B47: return lex_Matra_pre;
2624 case 0x0B4D: return lex_Halant;
2625 case 0x200C: return lex_ZWNJ;
2626 case 0x200D: return lex_ZWJ;
2627 default:
2628 if (c>=0x0B01 && c<=0x0B03) return lex_Modifier;
2629 else if (c>=0x0B05 && c<=0x0B14) return lex_Vowel;
2630 else if (c>=0x0B15 && c<=0x0B39) return lex_Consonant;
2631 else if (c>=0x0B41 && c<=0x0B44) return lex_Matra_below;
2632 else if (c>=0x0B48 && c<=0x0B4C) return lex_Composed_Vowel;
2633 else if (c>=0x0B5C && c<=0x0B5D) return lex_Consonant;
2634 else if (c>=0x0B60 && c<=0x0B61) return lex_Vowel;
2635 else if (c>=0x0B62 && c<=0x0B63) return lex_Matra_below;
2636 else return lex_Generic;
2640 static const VowelComponents Oriya_vowels[] = {
2641 {0x0B48, {0x0B47,0x0B56,0x0000}},
2642 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2643 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2644 {0x0000, {0x0000,0x0000,0x0000}}};
2646 static const ConsonantComponents Oriya_consonants[] = {
2647 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2648 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2649 {{0x0000,0x0000,0x0000}, 0x0000}};
2651 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2653 int cCount = cChars;
2654 WCHAR *input;
2655 IndicSyllable *syllables = NULL;
2656 int syllable_count = 0;
2657 BOOL modern = get_GSUB_Indic2(psa, psc);
2659 if (*pcGlyphs != cChars)
2661 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2662 return;
2665 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2666 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2668 /* Step 1: Decompose Vowels and Compose Consonents */
2669 DecomposeVowels(hdc, input, &cCount, Oriya_vowels);
2670 ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2671 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2673 /* Step 2: Reorder within Syllables */
2674 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2675 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2676 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2677 *pcGlyphs = cCount;
2679 /* Step 3: Base Form application to syllables */
2680 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2682 HeapFree(GetProcessHeap(),0,input);
2683 HeapFree(GetProcessHeap(),0,syllables);
2686 static int tamil_lex(WCHAR c)
2688 switch (c)
2690 case 0x0BC0: return lex_Matra_above;
2691 case 0x0BCD: return lex_Halant;
2692 case 0x0BD7: return lex_Matra_post;
2693 case 0x200C: return lex_ZWNJ;
2694 case 0x200D: return lex_ZWJ;
2695 default:
2696 if (c>=0x0B95 && c<=0x0BB9) return lex_Consonant;
2697 else if (c>=0x0BBE && c<=0x0BBF) return lex_Matra_post;
2698 else if (c>=0x0BC1 && c<=0x0BC2) return lex_Matra_below;
2699 else if (c>=0x0BC6 && c<=0x0BC8) return lex_Matra_pre;
2700 else return lex_Generic;
2704 static const VowelComponents Tamil_vowels[] = {
2705 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2706 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2707 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2708 {0x0000, {0x0000,0x0000,0x0000}}};
2710 static const ConsonantComponents Tamil_consonants[] = {
2711 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2712 {{0x0000,0x0000,0x0000}, 0x0000}};
2714 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2716 int cCount = cChars;
2717 WCHAR *input;
2718 IndicSyllable *syllables = NULL;
2719 int syllable_count = 0;
2720 BOOL modern = get_GSUB_Indic2(psa, psc);
2722 if (*pcGlyphs != cChars)
2724 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2725 return;
2728 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2729 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2731 /* Step 1: Decompose Vowels and Compose Consonents */
2732 DecomposeVowels(hdc, input, &cCount, Tamil_vowels);
2733 ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2734 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2736 /* Step 2: Reorder within Syllables */
2737 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2738 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2739 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2740 *pcGlyphs = cCount;
2742 /* Step 3: Base Form application to syllables */
2743 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2745 HeapFree(GetProcessHeap(),0,input);
2746 HeapFree(GetProcessHeap(),0,syllables);
2749 static int telugu_lex(WCHAR c)
2751 switch (c)
2753 case 0x0C4D: return lex_Halant;
2754 case 0x0C55: return lex_Matra_above;
2755 case 0x0C56: return lex_Matra_below;
2756 case 0x200C: return lex_ZWNJ;
2757 case 0x200D: return lex_ZWJ;
2758 default:
2759 if (c>=0x0C01 && c<=0x0C03) return lex_Modifier;
2760 else if (c>=0x0C05 && c<=0x0C14) return lex_Vowel;
2761 else if (c>=0x0C15 && c<=0x0C39) return lex_Consonant;
2762 else if (c>=0x0C3E && c<=0x0C40) return lex_Matra_above;
2763 else if (c>=0x0C41 && c<=0x0C42) return lex_Matra_post;
2764 else if (c>=0x0C43 && c<=0x0C44) return lex_Modifier;
2765 else if (c>=0x0C46 && c<=0x0C47) return lex_Matra_above;
2766 else if (c>=0x0C4A && c<=0x0C4C) return lex_Matra_above;
2767 else if (c>=0x0C58 && c<=0x0C59) return lex_Consonant;
2768 else if (c>=0x0C60 && c<=0x0C61) return lex_Vowel;
2769 else if (c>=0x0C62 && c<=0x0C63) return lex_Modifier;
2770 else return lex_Generic;
2774 static const VowelComponents Telugu_vowels[] = {
2775 {0x0C48, {0x0C46,0x0C56,0x0000}},
2776 {0x0000, {0x0000,0x0000,0x0000}}};
2778 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2780 int cCount = cChars;
2781 WCHAR *input;
2782 IndicSyllable *syllables = NULL;
2783 int syllable_count = 0;
2784 BOOL modern = get_GSUB_Indic2(psa, psc);
2786 if (*pcGlyphs != cChars)
2788 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2789 return;
2792 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2793 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2795 /* Step 1: Decompose Vowels */
2796 DecomposeVowels(hdc, input, &cCount, Telugu_vowels);
2797 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2799 /* Step 2: Reorder within Syllables */
2800 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2801 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2802 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2803 *pcGlyphs = cCount;
2805 /* Step 3: Base Form application to syllables */
2806 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2808 HeapFree(GetProcessHeap(),0,input);
2809 HeapFree(GetProcessHeap(),0,syllables);
2812 static int kannada_lex(WCHAR c)
2814 switch (c)
2816 case 0x0CB0: return lex_Ra;
2817 case 0x0CBC: return lex_Nukta;
2818 case 0x0CBE: return lex_Matra_post;
2819 case 0x0CBF: return lex_Matra_above;
2820 case 0x0CC6: return lex_Matra_above;
2821 case 0x0CCC: return lex_Matra_above;
2822 case 0x0CCD: return lex_Halant;
2823 case 0x0CCE: return lex_Consonant;
2824 case 0x200C: return lex_ZWNJ;
2825 case 0x200D: return lex_ZWJ;
2826 default:
2827 if (c>=0x0C82 && c<=0x0C83) return lex_Modifier;
2828 else if (c>=0x0C85 && c<=0x0C94) return lex_Vowel;
2829 else if (c>=0x0C95 && c<=0x0CB9) return lex_Consonant;
2830 else if (c>=0x0CC1 && c<=0x0CC4) return lex_Matra_post;
2831 else if (c>=0x0CD5 && c<=0x0CD6) return lex_Modifier;
2832 else if (c>=0x0CE0 && c<=0x0CE1) return lex_Vowel;
2833 else if (c>=0x0CE2 && c<=0x0CE3) return lex_Matra_below;
2834 else return lex_Generic;
2838 static const VowelComponents Kannada_vowels[] = {
2839 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2840 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2841 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2842 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2843 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2844 {0x0000, {0x0000,0x0000,0x0000}}};
2846 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2848 int cCount = cChars;
2849 WCHAR *input;
2850 IndicSyllable *syllables = NULL;
2851 int syllable_count = 0;
2852 BOOL modern = get_GSUB_Indic2(psa, psc);
2854 if (*pcGlyphs != cChars)
2856 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2857 return;
2860 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2861 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2863 /* Step 1: Decompose Vowels */
2864 DecomposeVowels(hdc, input, &cCount, Kannada_vowels);
2865 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2867 /* Step 2: Reorder within Syllables */
2868 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2869 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2870 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2871 *pcGlyphs = cCount;
2873 /* Step 3: Base Form application to syllables */
2874 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2876 HeapFree(GetProcessHeap(),0,input);
2877 HeapFree(GetProcessHeap(),0,syllables);
2880 static int malayalam_lex(WCHAR c)
2882 switch (c)
2884 case 0x0D35: return lex_Consonant;
2885 case 0x0D4D: return lex_Halant;
2886 case 0x0D57: return lex_Matra_post;
2887 case 0x200C: return lex_ZWNJ;
2888 case 0x200D: return lex_ZWJ;
2889 default:
2890 if (c>=0x0D02 && c<=0x0D03) return lex_Modifier;
2891 else if (c>=0x0D05 && c<=0x0D14) return lex_Vowel;
2892 else if (c>=0x0D15 && c<=0x0D39) return lex_Consonant;
2893 else if (c>=0x0D3E && c<=0x0D44) return lex_Matra_post;
2894 else if (c>=0x0D46 && c<=0x0D48) return lex_Matra_pre;
2895 else if (c>=0x0D60 && c<=0x0D61) return lex_Vowel;
2896 else if (c>=0x0D62 && c<=0x0D63) return lex_Matra_below;
2897 else return lex_Generic;
2901 static const VowelComponents Malayalam_vowels[] = {
2902 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2903 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2904 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2905 {0x0000, {0x0000,0x0000,0x0000}}};
2907 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2909 int cCount = cChars;
2910 WCHAR *input;
2911 IndicSyllable *syllables = NULL;
2912 int syllable_count = 0;
2913 BOOL modern = get_GSUB_Indic2(psa, psc);
2915 if (*pcGlyphs != cChars)
2917 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2918 return;
2921 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2922 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2924 /* Step 1: Decompose Vowels */
2925 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels);
2926 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2928 /* Step 2: Reorder within Syllables */
2929 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2930 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2931 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2932 *pcGlyphs = cCount;
2934 /* Step 3: Base Form application to syllables */
2935 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2937 HeapFree(GetProcessHeap(),0,input);
2938 HeapFree(GetProcessHeap(),0,syllables);
2941 static void ShapeCharGlyphProp_Default( 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,k;
2945 for (i = 0; i < cGlyphs; i++)
2947 int char_index[20];
2948 int char_count = 0;
2950 for (k = 0; k < cChars; k++)
2952 if (pwLogClust[k] == i)
2954 char_index[char_count] = k;
2955 char_count++;
2959 if (char_count == 0)
2961 FIXME("No chars in this glyph? Must be an error\n");
2962 continue;
2965 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2967 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2968 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2970 else
2971 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2974 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2975 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2978 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 )
2980 int i,k;
2981 int initGlyph, finaGlyph;
2982 INT dirR, dirL;
2983 BYTE *spaces;
2985 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2986 memset(spaces,0,cGlyphs);
2988 if (!psa->fLogicalOrder && psa->fRTL)
2990 initGlyph = cGlyphs-1;
2991 finaGlyph = 0;
2992 dirR = 1;
2993 dirL = -1;
2995 else
2997 initGlyph = 0;
2998 finaGlyph = cGlyphs-1;
2999 dirR = -1;
3000 dirL = 1;
3003 for (i = 0; i < cGlyphs; i++)
3005 for (k = 0; k < cChars; k++)
3006 if (pwLogClust[k] == i)
3008 if (pwcChars[k] == 0x0020)
3009 spaces[i] = 1;
3013 for (i = 0; i < cGlyphs; i++)
3015 int char_index[20];
3016 int char_count = 0;
3017 BOOL isInit, isFinal;
3019 for (k = 0; k < cChars; k++)
3021 if (pwLogClust[k] == i)
3023 char_index[char_count] = k;
3024 char_count++;
3028 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3029 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3031 if (char_count == 0)
3033 FIXME("No chars in this glyph? Must be an error\n");
3034 continue;
3037 if (char_count == 1)
3039 if (pwcChars[char_index[0]] == 0x0020) /* space */
3041 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3042 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3044 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3045 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3046 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3048 if (!isInit && !isFinal)
3049 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3050 else if (isInit)
3051 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3052 else
3053 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3055 else if (!isInit)
3057 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3058 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3059 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3060 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3061 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3062 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3063 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3064 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3065 else
3066 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3068 else if (!isInit && !isFinal)
3069 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3070 else
3071 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3073 else if (char_count == 2)
3075 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3076 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3077 else if (!isInit)
3078 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3079 else
3080 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3082 else if (!isInit && !isFinal)
3083 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3084 else
3085 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3088 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3089 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3090 HeapFree(GetProcessHeap(),0,spaces);
3093 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 )
3095 int i,k;
3096 int finaGlyph;
3097 INT dirL;
3098 BYTE *spaces;
3100 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3101 memset(spaces,0,cGlyphs);
3103 if (!psa->fLogicalOrder && psa->fRTL)
3105 finaGlyph = 0;
3106 dirL = -1;
3108 else
3110 finaGlyph = cGlyphs-1;
3111 dirL = 1;
3114 for (i = 0; i < cGlyphs; i++)
3116 for (k = 0; k < cChars; k++)
3117 if (pwLogClust[k] == i)
3119 if (pwcChars[k] == 0x0020)
3120 spaces[i] = 1;
3124 for (i = 0; i < cGlyphs; i++)
3126 int char_index[20];
3127 int char_count = 0;
3129 for (k = 0; k < cChars; k++)
3131 if (pwLogClust[k] == i)
3133 char_index[char_count] = k;
3134 char_count++;
3138 if (char_count == 0)
3140 FIXME("No chars in this glyph? Must be an error\n");
3141 continue;
3144 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3146 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3147 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3149 else if (i == finaGlyph)
3150 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3151 else
3152 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3155 HeapFree(GetProcessHeap(),0,spaces);
3156 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3157 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3159 /* Do not allow justification between marks and their base */
3160 for (i = 0; i < cGlyphs; i++)
3162 if (!pGlyphProp[i].sva.fClusterStart)
3163 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3167 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
3169 int i,k;
3171 for (i = 0; i < cGlyphs; i++)
3173 int char_index[20];
3174 int char_count = 0;
3176 for (k = 0; k < cChars; k++)
3178 if (pwLogClust[k] == i)
3180 char_index[char_count] = k;
3181 char_count++;
3185 if (char_count == 0)
3187 FIXME("No chars in this glyph? Must be an error\n");
3188 continue;
3191 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3193 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3194 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3196 else
3197 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3199 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3200 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3203 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)
3205 int i,k;
3207 for (i = 0; i < cGlyphs; i++)
3209 int char_index[20];
3210 int char_count = 0;
3212 for (k = 0; k < cChars; k++)
3214 if (pwLogClust[k] == i)
3216 char_index[char_count] = k;
3217 char_count++;
3221 if (char_count == 0)
3223 FIXME("No chars in this glyph? Must be an error\n");
3224 continue;
3227 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3229 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3230 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3232 else
3233 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3235 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3236 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3238 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3239 for (i = 0; i < cGlyphs; i++)
3241 if (!pGlyphProp[i].sva.fClusterStart)
3243 pGlyphProp[i].sva.fDiacritic = 0;
3244 pGlyphProp[i].sva.fZeroWidth = 0;
3249 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)
3251 int i,k;
3253 for (i = 0; i < cGlyphs; i++)
3255 int char_index[20];
3256 int char_count = 0;
3258 for (k = 0; k < cChars; k++)
3260 if (pwLogClust[k] == i)
3262 char_index[char_count] = k;
3263 char_count++;
3267 if (char_count == 0)
3269 FIXME("No chars in this glyph? Must be an error\n");
3270 continue;
3273 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3275 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3276 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3278 else
3279 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3281 pGlyphProp[i].sva.fClusterStart = 0;
3282 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3283 switch (lexical(pwcChars[char_index[k]]))
3285 case lex_Matra_pre:
3286 case lex_Matra_post:
3287 case lex_Matra_above:
3288 case lex_Matra_below:
3289 case lex_Modifier:
3290 break;
3291 default:
3292 pGlyphProp[i].sva.fClusterStart = 1;
3293 break;
3296 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3299 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 )
3301 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3304 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 )
3306 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3309 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 )
3311 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3314 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 )
3316 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3319 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 )
3321 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3324 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 )
3326 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3329 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 )
3331 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3334 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 )
3336 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3339 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 )
3341 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3344 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)
3346 if (ShapingData[psa->eScript].charGlyphPropProc)
3347 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3348 else
3349 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3352 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3354 if (ShapingData[psa->eScript].contextProc)
3355 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3358 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)
3360 int i;
3361 INT dirL;
3363 if (!rpRangeProperties)
3364 return;
3366 if (!psc->GSUB_Table)
3367 psc->GSUB_Table = load_gsub_table(hdc);
3369 if (!psc->GSUB_Table)
3370 return;
3372 if (!psa->fLogicalOrder && psa->fRTL)
3373 dirL = -1;
3374 else
3375 dirL = 1;
3377 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3379 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3380 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3384 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3386 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3387 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3389 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3392 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3394 const GSUB_Feature *feature;
3395 int i;
3397 if (!ShapingData[psa->eScript].requiredFeatures)
3398 return S_OK;
3400 if (!psc->GSUB_Table)
3401 psc->GSUB_Table = load_gsub_table(hdc);
3403 /* we need to have at least one of the required features */
3404 i = 0;
3405 while (ShapingData[psa->eScript].requiredFeatures[i])
3407 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3408 if (feature)
3409 return S_OK;
3410 i++;
3413 return USP_E_SCRIPT_NOT_IN_FONT;