usp10: Correct Post Base glyph index shifting.
[wine/multimedia.git] / dlls / usp10 / shape.c
blob104757c74ff82ca84afb1b5766c4fb7a4381f026
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 WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1356 if (i + delta < 0)
1357 return 0;
1358 if ( i+ delta >= cchLen)
1359 return 0;
1361 i += delta;
1363 return chars[i];
1366 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1368 if (i + delta < 0)
1370 if (psa->fLinkBefore)
1371 return jtR;
1372 else
1373 return jtU;
1375 if ( i+ delta >= cchLen)
1377 if (psa->fLinkAfter)
1378 return jtL;
1379 else
1380 return jtU;
1383 i += delta;
1385 if (context_type[i] == jtT)
1386 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1387 else
1388 return context_type[i];
1391 static inline BOOL right_join_causing(CHAR joining_type)
1393 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1396 static inline BOOL left_join_causing(CHAR joining_type)
1398 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1401 static inline BOOL word_break_causing(WCHAR chr)
1403 /* we are working within a string of characters already guareented to
1404 be within one script, Syriac, so we do not worry about any characers
1405 other than the space character outside of that range */
1406 return (chr == 0 || chr == 0x20 );
1410 * ContextualShape_Arabic
1412 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1414 CHAR *context_type;
1415 INT *context_shape;
1416 INT dirR, dirL;
1417 int i;
1419 if (*pcGlyphs != cChars)
1421 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1422 return;
1425 if (!psa->fLogicalOrder && psa->fRTL)
1427 dirR = 1;
1428 dirL = -1;
1430 else
1432 dirR = -1;
1433 dirL = 1;
1436 if (!psc->GSUB_Table)
1437 psc->GSUB_Table = load_gsub_table(hdc);
1439 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1440 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1442 for (i = 0; i < cChars; i++)
1443 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1445 for (i = 0; i < cChars; i++)
1447 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1448 context_shape[i] = Xr;
1449 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1450 context_shape[i] = Xl;
1451 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)))
1452 context_shape[i] = Xm;
1453 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1454 context_shape[i] = Xr;
1455 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1456 context_shape[i] = Xl;
1457 else
1458 context_shape[i] = Xn;
1461 /* Contextual Shaping */
1462 i = 0;
1463 while(i < *pcGlyphs)
1465 BOOL shaped = FALSE;
1467 if (psc->GSUB_Table)
1469 INT nextIndex;
1470 INT prevCount = *pcGlyphs;
1471 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1472 if (nextIndex > GSUB_E_NOGLYPH)
1474 i = nextIndex;
1475 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1477 shaped = (nextIndex > GSUB_E_NOGLYPH);
1480 if (!shaped)
1482 WORD newGlyph = pwOutGlyphs[i];
1483 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1485 /* fall back to presentation form B */
1486 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1487 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1488 pwOutGlyphs[i] = newGlyph;
1490 i++;
1494 HeapFree(GetProcessHeap(),0,context_shape);
1495 HeapFree(GetProcessHeap(),0,context_type);
1499 * ContextualShape_Syriac
1502 #define ALAPH 0x710
1503 #define DALATH 0x715
1504 #define RISH 0x72A
1506 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1508 CHAR *context_type;
1509 INT *context_shape;
1510 INT dirR, dirL;
1511 int i;
1513 if (*pcGlyphs != cChars)
1515 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1516 return;
1519 if (!psa->fLogicalOrder && psa->fRTL)
1521 dirR = 1;
1522 dirL = -1;
1524 else
1526 dirR = -1;
1527 dirL = 1;
1530 if (!psc->GSUB_Table)
1531 psc->GSUB_Table = load_gsub_table(hdc);
1533 if (!psc->GSUB_Table)
1534 return;
1536 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1537 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1539 for (i = 0; i < cChars; i++)
1540 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1542 for (i = 0; i < cChars; i++)
1544 if (pwcChars[i] == ALAPH)
1546 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1548 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1549 context_shape[i] = Afj;
1550 else if ( rchar != DALATH && rchar != RISH &&
1551 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1552 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1553 context_shape[i] = Afn;
1554 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1555 context_shape[i] = Afx;
1556 else
1557 context_shape[i] = Xn;
1559 else if (context_type[i] == jtR &&
1560 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1561 context_shape[i] = Xr;
1562 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1563 context_shape[i] = Xl;
1564 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)))
1565 context_shape[i] = Xm;
1566 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1567 context_shape[i] = Xr;
1568 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1569 context_shape[i] = Xl;
1570 else
1571 context_shape[i] = Xn;
1574 /* Contextual Shaping */
1575 i = 0;
1576 while(i < *pcGlyphs)
1578 INT nextIndex;
1579 INT prevCount = *pcGlyphs;
1580 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1581 if (nextIndex > GSUB_E_NOGLYPH)
1583 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1584 i = nextIndex;
1586 else
1587 i++;
1590 HeapFree(GetProcessHeap(),0,context_shape);
1591 HeapFree(GetProcessHeap(),0,context_type);
1595 * ContextualShape_Phags_pa
1598 #define phags_pa_CANDRABINDU 0xA873
1599 #define phags_pa_START 0xA840
1600 #define phags_pa_END 0xA87F
1602 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1604 INT *context_shape;
1605 INT dirR, dirL;
1606 int i;
1608 if (*pcGlyphs != cChars)
1610 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1611 return;
1614 if (!psa->fLogicalOrder && psa->fRTL)
1616 dirR = 1;
1617 dirL = -1;
1619 else
1621 dirR = -1;
1622 dirL = 1;
1625 if (!psc->GSUB_Table)
1626 psc->GSUB_Table = load_gsub_table(hdc);
1628 if (!psc->GSUB_Table)
1629 return;
1631 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1633 for (i = 0; i < cChars; i++)
1635 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1637 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1638 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1639 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1640 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1642 if (jrchar && jlchar)
1643 context_shape[i] = Xm;
1644 else if (jrchar)
1645 context_shape[i] = Xr;
1646 else if (jlchar)
1647 context_shape[i] = Xl;
1648 else
1649 context_shape[i] = Xn;
1651 else
1652 context_shape[i] = -1;
1655 /* Contextual Shaping */
1656 i = 0;
1657 while(i < *pcGlyphs)
1659 if (context_shape[i] >= 0)
1661 INT nextIndex;
1662 INT prevCount = *pcGlyphs;
1663 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1664 if (nextIndex > GSUB_E_NOGLYPH)
1666 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1667 i = nextIndex;
1669 else
1670 i++;
1672 else
1673 i++;
1676 HeapFree(GetProcessHeap(),0,context_shape);
1679 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1681 int i;
1683 /* Replace */
1684 pwOutChars[cWalk] = replacements[0];
1685 cWalk=cWalk+1;
1687 /* Insert */
1688 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1690 int j;
1691 for (j = *pcChars; j > cWalk; j--)
1692 pwOutChars[j] = pwOutChars[j-1];
1693 *pcChars= *pcChars+1;
1694 pwOutChars[cWalk] = replacements[i];
1695 cWalk = cWalk+1;
1699 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1701 int i;
1702 int cWalk;
1704 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1706 for (i = 0; vowels[i].base != 0x0; i++)
1708 if (pwOutChars[cWalk] == vowels[i].base)
1710 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1711 if (vowels[i].parts[1]) cWalk++;
1712 if (vowels[i].parts[2]) cWalk++;
1713 break;
1719 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1721 int i;
1722 int cWalk;
1724 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1726 for (i = 0; consonants[i].output!= 0x0; i++)
1728 int j;
1729 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1730 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1731 break;
1733 if (consonants[i].parts[j]==0x0) /* matched all */
1735 int k;
1736 j--;
1737 pwOutChars[cWalk] = consonants[i].output;
1738 for(k = cWalk+1; k < *pcChars - j; k++)
1739 pwOutChars[k] = pwOutChars[k+j];
1740 *pcChars = *pcChars - j;
1741 break;
1744 cWalk++;
1748 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1750 if (s->ralf >= 0)
1752 int j;
1753 WORD Ra = pwChar[s->start];
1754 WORD H = pwChar[s->start+1];
1756 TRACE("Doing reorder of Ra to %i\n",s->base);
1757 for (j = s->start; j < s->base-1; j++)
1758 pwChar[j] = pwChar[j+2];
1759 pwChar[s->base-1] = Ra;
1760 pwChar[s->base] = H;
1762 s->ralf = s->base-1;
1763 s->base -= 2;
1767 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1769 if (s->ralf >= 0)
1771 int j,loc;
1772 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1773 WORD Ra = pwChar[s->start];
1774 WORD H = pwChar[s->start+1];
1775 for (loc = s->end; loc > stop; loc--)
1776 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1777 break;
1779 TRACE("Doing reorder of Ra to %i\n",loc);
1780 for (j = s->start; j < loc-1; j++)
1781 pwChar[j] = pwChar[j+2];
1782 pwChar[loc-1] = Ra;
1783 pwChar[loc] = H;
1785 s->ralf = loc-1;
1786 s->base -= 2;
1787 if (s->blwf >= 0) s->blwf -= 2;
1788 if (s->pref >= 0) s->pref -= 2;
1792 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1794 if (s->ralf >= 0)
1796 int j;
1797 WORD Ra = pwChar[s->start];
1798 WORD H = pwChar[s->start+1];
1800 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1801 for (j = s->start; j < s->end-1; j++)
1802 pwChar[j] = pwChar[j+2];
1803 pwChar[s->end-1] = Ra;
1804 pwChar[s->end] = H;
1806 s->ralf = s->end-1;
1807 s->base -= 2;
1808 if (s->blwf >= 0) s->blwf -= 2;
1809 if (s->pref >= 0) s->pref -= 2;
1813 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1815 int i;
1817 /* reorder Matras */
1818 if (s->end > s->base)
1820 for (i = 1; i <= s->end-s->base; i++)
1822 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1824 int j;
1825 WCHAR c = pwChar[s->base+i];
1826 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1827 for (j = s->base+i; j > s->base; j--)
1828 pwChar[j] = pwChar[j-1];
1829 pwChar[s->base] = c;
1831 if (s->ralf >= s->base) s->ralf++;
1832 if (s->blwf >= s->base) s->blwf++;
1833 if (s->pref >= s->base) s->pref++;
1834 s->base ++;
1840 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1842 int i;
1844 /* reorder Matras */
1845 if (s->end > s->base)
1847 for (i = 1; i <= s->end-s->base; i++)
1849 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1851 int j;
1852 WCHAR c = pwChar[s->base+i];
1853 TRACE("Doing reorder of %x to %i\n",c,s->start);
1854 for (j = s->base+i; j > s->start; j--)
1855 pwChar[j] = pwChar[j-1];
1856 pwChar[s->start] = c;
1858 if (s->ralf >= 0) s->ralf++;
1859 if (s->blwf >= 0) s->blwf++;
1860 if (s->pref >= 0) s->pref++;
1861 s->base ++;
1867 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1869 if (s->blwf >= 0 && g->blwf > g->base)
1871 int j,loc;
1872 int g_offset;
1873 for (loc = s->end; loc > s->blwf; loc--)
1874 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1875 break;
1877 g_offset = (loc - s->blwf) - 1;
1879 if (loc != s->blwf)
1881 WORD blwf = glyphs[g->blwf];
1882 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1883 /* do not care about the pwChar array anymore, just the glyphs */
1884 for (j = 0; j < g_offset; j++)
1885 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1886 glyphs[g->blwf + g_offset] = blwf;
1891 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1893 int i;
1895 /* reorder previously moved Matras to correct position*/
1896 for (i = s->start; i < s->base; i++)
1898 if (lexical(pwChar[i]) == lex_Matra_pre)
1900 int j;
1901 int g_start = g->start + i - s->start;
1902 if (g_start < g->base -1 )
1904 WCHAR og = glyphs[g_start];
1905 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1906 for (j = g_start; j < g->base-1; j++)
1907 glyphs[j] = glyphs[j+1];
1908 glyphs[g->base-1] = og;
1914 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1916 if (s->pref >= 0 && g->pref > g->base)
1918 int j;
1919 WCHAR og = glyphs[g->pref];
1920 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1921 for (j = g->pref; j > g->base; j--)
1922 glyphs[j] = glyphs[j-1];
1923 glyphs[g->base] = og;
1927 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1929 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1930 if (s->start == s->base && s->base == s->end) return;
1931 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1933 Reorder_Ra_follows_base(pwChar, s, lexical);
1934 Reorder_Matra_precede_base(pwChar, s, lexical);
1937 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1939 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1940 if (s->start == s->base && s->base == s->end) return;
1941 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1943 Reorder_Ra_follows_matra(pwChar, s, lexical);
1944 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1947 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1949 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1950 if (s->start == s->base && s->base == s->end) return;
1951 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1953 Reorder_Ra_follows_base(pwChar, s, lexical);
1954 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1957 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1959 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1960 if (s->start == s->base && s->base == s->end) return;
1961 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1963 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1964 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1967 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1969 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1970 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1971 if (s->start == s->base && s->base == s->end) return;
1972 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1974 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1977 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1979 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1980 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1981 if (s->start == s->base && s->base == s->end) return;
1982 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1984 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1985 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1989 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1991 if (shift == 0)
1992 return;
1994 if (glyph_index->start > index)
1995 glyph_index->start += shift;
1996 if (glyph_index->base > index)
1997 glyph_index->base+= shift;
1998 if (glyph_index->end > index)
1999 glyph_index->end+= shift;
2000 if (glyph_index->ralf > index)
2001 glyph_index->ralf+= shift;
2002 if (glyph_index->blwf > index)
2003 glyph_index->blwf+= shift;
2004 if (glyph_index->pref > index)
2005 glyph_index->pref+= shift;
2008 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 )
2010 int index = glyph_index->start;
2012 if (!feature)
2013 return;
2015 while(index <= glyph_index->end)
2017 INT nextIndex;
2018 INT prevCount = *pcGlyphs;
2019 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2020 if (nextIndex > GSUB_E_NOGLYPH)
2022 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2023 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2024 index = nextIndex;
2026 else
2027 index++;
2031 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2033 int i = 0;
2034 while (i + index < end - 1 && !(lexical(pwChars[index+i]) == lex_Consonant && (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)))))
2035 i++;
2036 if (index + i <= end-1)
2037 return index + i;
2038 else
2039 return -1;
2042 static void Apply_Indic_Half(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)
2044 INT index, nextIndex;
2045 INT count,g_offset;
2046 INT prevCount = *pcGlyphs;
2048 count = syllable->base - syllable->start;
2050 g_offset = 0;
2051 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2052 while (index >= 0 && index < (glyph_index->base - glyph_index->start))
2054 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, "half");
2055 if (nextIndex > GSUB_E_NOGLYPH)
2057 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2058 g_offset += (*pcGlyphs - prevCount);
2059 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start, g_offset);
2062 index+=2;
2063 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2067 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)
2069 INT nextIndex;
2070 INT prevCount = *pcGlyphs;
2072 if (syllable->ralf >= 0)
2074 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2075 if (nextIndex > GSUB_E_NOGLYPH)
2077 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2078 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2083 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2085 int i = 0;
2086 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2087 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2088 is_consonant(lexical(pwChars[index+i+1])))))
2089 i++;
2090 if (index + i <= end-1)
2091 return index+i;
2092 else
2093 return -1;
2096 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, const char* feat)
2098 INT index, nextIndex;
2099 INT count, g_offset;
2101 count = syllable->end - syllable->base;
2103 if (syllable->ralf >= syllable->base)
2104 g_offset = -1;
2105 else
2106 g_offset = 0;
2107 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2109 while (index >= 0)
2111 INT prevCount = *pcGlyphs;
2112 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2113 if (nextIndex > GSUB_E_NOGLYPH)
2115 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2116 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2117 g_offset += (*pcGlyphs - prevCount);
2120 index+=2;
2121 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2125 static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllables, INT syllable_count, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, second_reorder_function second_reorder)
2127 int c;
2128 int overall_shift = 0;
2129 const GSUB_Feature *locl = load_GSUB_feature(hdc, psa, psc, "locl");
2130 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2131 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2132 const GSUB_Feature *rkrf = load_GSUB_feature(hdc, psa, psc, "rkrf");
2133 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2134 const GSUB_Feature *vatu = load_GSUB_feature(hdc, psa, psc, "vatu");
2135 const GSUB_Feature *cjct = load_GSUB_feature(hdc, psa, psc, "cjct");
2136 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2137 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2138 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2139 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2140 IndicSyllable glyph_indexs;
2142 for (c = 0; c < syllable_count; c++)
2144 int old_end;
2145 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2146 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2147 old_end = glyph_indexs.end;
2149 if (locl)
2151 TRACE("applying feature locl\n");
2152 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2154 if (nukt)
2156 TRACE("applying feature nukt\n");
2157 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2159 if (akhn)
2161 TRACE("applying feature akhn\n");
2162 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2165 if (rphf)
2166 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2167 if (rkrf)
2169 TRACE("applying feature rkrf\n");
2170 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2172 if (pref)
2173 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "pref");
2174 if (blwf)
2175 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2176 if (half)
2177 Apply_Indic_Half(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2178 if (pstf)
2180 TRACE("applying feature pstf\n");
2181 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2183 if (vatu)
2185 TRACE("applying feature vatu\n");
2186 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2188 if (cjct)
2190 TRACE("applying feature cjct\n");
2191 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2194 if (second_reorder)
2195 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2197 overall_shift += glyph_indexs.end - old_end;
2201 static int sinhala_lex(WCHAR c)
2203 switch (c)
2205 case 0x0DCA: return lex_Halant;
2206 case 0x0DCF:
2207 case 0x0DDF:
2208 case 0x0DD8: return lex_Matra_post;
2209 case 0x0DD9:
2210 case 0x0DDB: return lex_Matra_pre;
2211 case 0x0DDA:
2212 case 0x0DDC: return lex_Matra_post;
2213 case 0x200D: return lex_ZWJ;
2214 case 0x200C: return lex_ZWNJ;
2215 case 0x00A0: return lex_NBSP;
2216 default:
2217 if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
2218 else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
2219 else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
2220 else if (c>=0x0DD0 && c <=0x0DD1) return lex_Matra_post;
2221 else if (c>=0x0DD2 && c <=0x0DD3) return lex_Matra_above;
2222 else if (c>=0x0DD4 && c <=0x0DD6) return lex_Matra_below;
2223 else if (c>=0x0DDD && c <=0x0DDE) return lex_Matra_post;
2224 else if (c>=0x0DF2 && c <=0x0DF3) return lex_Matra_post;
2225 else return lex_Generic;
2229 static const VowelComponents Sinhala_vowels[] = {
2230 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2231 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2232 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2233 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2234 {0x0000, {0x0000,0x0000,0x0}}};
2236 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2238 int cCount = cChars;
2239 int i;
2240 WCHAR *input;
2241 IndicSyllable *syllables = NULL;
2242 int syllable_count = 0;
2244 if (*pcGlyphs != cChars)
2246 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2247 return;
2250 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2252 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2254 /* Step 1: Decompose multi part vowels */
2255 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels);
2257 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2259 /* Step 2: Reorder within Syllables */
2260 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala);
2261 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2263 /* Step 3: Strip dangling joiners */
2264 for (i = 0; i < cCount; i++)
2266 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2267 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2268 input[i] = 0x0020;
2271 /* Step 4: Base Form application to syllables */
2272 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2273 *pcGlyphs = cCount;
2274 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL);
2276 HeapFree(GetProcessHeap(),0,input);
2277 HeapFree(GetProcessHeap(),0,syllables);
2280 static int devanagari_lex(WCHAR c)
2282 switch (c)
2284 case 0x0951:
2285 case 0x0952:
2286 case 0x0903: return lex_Modifier;
2287 case 0x0930: return lex_Ra;
2288 case 0x093C: return lex_Nukta;
2289 case 0x0940:
2290 case 0x093E: return lex_Matra_post;
2291 case 0x093F: return lex_Matra_pre;
2292 case 0x094D: return lex_Halant;
2293 case 0x0972: return lex_Vowel;
2294 case 0x200C: return lex_ZWNJ;
2295 case 0x200D: return lex_ZWJ;
2296 default:
2297 if (c>=0x0901 && c<=0x0902) return lex_Matra_above;
2298 else if (c>=0x0904 && c<=0x0914) return lex_Vowel;
2299 else if (c>=0x0915 && c<=0x0939) return lex_Consonant;
2300 else if (c>=0x0941 && c<=0x0944) return lex_Matra_below;
2301 else if (c>=0x0945 && c<=0x0948) return lex_Matra_above;
2302 else if (c>=0x0949 && c<=0x094C) return lex_Matra_post;
2303 else if (c>=0x0953 && c<=0x0954) return lex_Modifier;
2304 else if (c>=0x0958 && c<=0x095F) return lex_Consonant;
2305 else if (c>=0x0960 && c<=0x0961) return lex_Vowel;
2306 else if (c>=0x0962 && c<=0x0963) return lex_Matra_below;
2307 else if (c>=0x097B && c<=0x097C) return lex_Consonant;
2308 else if (c>=0x097E && c<=0x097F) return lex_Consonant;
2309 else return lex_Generic;
2313 static const ConsonantComponents Devanagari_consonants[] ={
2314 {{0x0928, 0x093C, 0x00000}, 0x0929},
2315 {{0x0930, 0x093C, 0x00000}, 0x0931},
2316 {{0x0933, 0x093C, 0x00000}, 0x0934},
2317 {{0x0915, 0x093C, 0x00000}, 0x0958},
2318 {{0x0916, 0x093C, 0x00000}, 0x0959},
2319 {{0x0917, 0x093C, 0x00000}, 0x095A},
2320 {{0x091C, 0x093C, 0x00000}, 0x095B},
2321 {{0x0921, 0x093C, 0x00000}, 0x095C},
2322 {{0x0922, 0x093C, 0x00000}, 0x095D},
2323 {{0x092B, 0x093C, 0x00000}, 0x095E},
2324 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2326 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2328 int cCount = cChars;
2329 WCHAR *input;
2330 IndicSyllable *syllables = NULL;
2331 int syllable_count = 0;
2333 if (*pcGlyphs != cChars)
2335 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2336 return;
2339 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2340 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2342 /* Step 1: Compose Consonant and Nukta */
2343 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2344 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2346 /* Step 2: Reorder within Syllables */
2347 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari);
2348 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2349 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2350 *pcGlyphs = cCount;
2352 /* Step 3: Base Form application to syllables */
2353 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL);
2355 HeapFree(GetProcessHeap(),0,input);
2356 HeapFree(GetProcessHeap(),0,syllables);
2359 static int bengali_lex(WCHAR c)
2361 switch (c)
2363 case 0x0981: return lex_Modifier;
2364 case 0x09AC:
2365 case 0x09AF:
2366 case 0x09CE: return lex_Consonant;
2367 case 0x09B0: return lex_Ra;
2368 case 0x09BC: return lex_Nukta;
2369 case 0x09BF: return lex_Matra_pre;
2370 case 0x09D7:
2371 case 0x09BE:
2372 case 0x09C0: return lex_Matra_post;
2373 case 0x09CD: return lex_Halant;
2374 case 0x200C: return lex_ZWNJ;
2375 case 0x200D: return lex_ZWJ;
2376 default:
2377 if (c>=0x0982 && c<=0x0983) return lex_Matra_post;
2378 else if (c>=0x0985 && c<=0x0994) return lex_Vowel;
2379 else if (c>=0x0995 && c<=0x09B9) return lex_Consonant;
2380 else if (c>=0x09C1 && c<=0x09C4) return lex_Matra_below;
2381 else if (c>=0x09C7 && c<=0x09C8) return lex_Matra_pre;
2382 else if (c>=0x09DC && c<=0x09DF) return lex_Consonant;
2383 else if (c>=0x09E0 && c<=0x09E1) return lex_Vowel;
2384 else if (c>=0x09E2 && c<=0x09E3) return lex_Matra_below;
2385 else if (c>=0x09F0 && c<=0x09F1) return lex_Consonant;
2386 else return lex_Generic;
2390 static const VowelComponents Bengali_vowels[] = {
2391 {0x09CB, {0x09C7,0x09BE,0x0000}},
2392 {0x09CC, {0x09C7,0x09D7,0x0000}},
2393 {0x0000, {0x0000,0x0000,0x0000}}};
2395 static const ConsonantComponents Bengali_consonants[] = {
2396 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2397 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2398 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2399 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2400 {{0x0000,0x0000,0x0000}, 0x0000}};
2402 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2404 int cCount = cChars;
2405 WCHAR *input;
2406 IndicSyllable *syllables = NULL;
2407 int syllable_count = 0;
2409 if (*pcGlyphs != cChars)
2411 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2412 return;
2415 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2416 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2418 /* Step 1: Decompose Vowels and Compose Consonents */
2419 DecomposeVowels(hdc, input, &cCount, Bengali_vowels);
2420 ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2421 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2423 /* Step 2: Reorder within Syllables */
2424 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali);
2425 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2426 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2427 *pcGlyphs = cCount;
2429 /* Step 3: Initial form is only applied to the beginning of words */
2430 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2432 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2434 int index = cCount;
2435 int gCount = 1;
2436 if (index > 0) index++;
2438 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2442 /* Step 4: Base Form application to syllables */
2443 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL);
2445 HeapFree(GetProcessHeap(),0,input);
2446 HeapFree(GetProcessHeap(),0,syllables);
2449 static int gurmukhi_lex(WCHAR c)
2451 switch (c)
2453 case 0x0A30:
2454 case 0x0A35:
2455 case 0x0A39:
2456 case 0x0A2f: return lex_Consonant;
2457 case 0x0A3C: return lex_Nukta;
2458 case 0x0A3F: return lex_Matra_pre;
2459 case 0x0A03:
2460 case 0x0A3E:
2461 case 0x0A40: return lex_Matra_post;
2462 case 0x0A4D: return lex_Halant;
2463 case 0x0A70:
2464 case 0x0A71: return lex_Modifier;
2465 case 0x200C: return lex_ZWNJ;
2466 case 0x200D: return lex_ZWJ;
2467 default:
2468 if (c>=0x0A01 && c<=0x0A02) return lex_Modifier;
2469 else if (c>=0x0A05 && c<=0x0A14) return lex_Vowel;
2470 else if (c>=0x0A15 && c<=0x0A38) return lex_Consonant;
2471 else if (c>=0x0A41 && c<=0x0A42) return lex_Matra_below;
2472 else if (c>=0x0A47 && c<=0x0A4C) return lex_Matra_above;
2473 else if (c>=0x0A59 && c<=0x0A5E) return lex_Consonant;
2474 else return lex_Generic;
2478 static const ConsonantComponents Gurmukhi_consonants[] = {
2479 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2480 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2481 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2482 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2483 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2484 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2485 {{0x0000,0x0000,0x0000}, 0x0000}};
2487 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2489 int cCount = cChars;
2490 WCHAR *input;
2491 IndicSyllable *syllables = NULL;
2492 int syllable_count = 0;
2494 if (*pcGlyphs != cChars)
2496 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2497 return;
2500 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2501 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2503 /* Step 1: Compose Consonents */
2504 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2505 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2507 /* Step 2: Reorder within Syllables */
2508 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali);
2509 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2510 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2511 *pcGlyphs = cCount;
2513 /* Step 3: Base Form application to syllables */
2514 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL);
2516 HeapFree(GetProcessHeap(),0,input);
2517 HeapFree(GetProcessHeap(),0,syllables);
2520 static int gujarati_lex(WCHAR c)
2522 switch (c)
2524 case 0x0A83: return lex_Modifier;
2525 case 0x0AB0: return lex_Ra;
2526 case 0x0ABC: return lex_Nukta;
2527 case 0x0ABF: return lex_Matra_pre;
2528 case 0x0ABE:
2529 case 0x0AC0: return lex_Matra_post;
2530 case 0x0ACD: return lex_Halant;
2531 case 0x200C: return lex_ZWNJ;
2532 case 0x200D: return lex_ZWJ;
2533 default:
2534 if (c>=0x0A81 && c<=0x0A82) return lex_Modifier;
2535 else if (c>=0x0A85 && c<=0x0A94) return lex_Vowel;
2536 else if (c>=0x0A95 && c<=0x0AB9) return lex_Consonant;
2537 else if (c>=0x0AC1 && c<=0x0AC4) return lex_Matra_below;
2538 else if (c>=0x0AC5 && c<=0x0AC8) return lex_Matra_above;
2539 else if (c>=0x0AC9 && c<=0x0ACC) return lex_Matra_post;
2540 else if (c>=0x0AE0 && c<=0x0AE1) return lex_Vowel;
2541 else if (c>=0x0AE2 && c<=0x0AE3) return lex_Matra_below;
2542 else return lex_Generic;
2546 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2548 int cCount = cChars;
2549 WCHAR *input;
2550 IndicSyllable *syllables = NULL;
2551 int syllable_count = 0;
2553 if (*pcGlyphs != cChars)
2555 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2556 return;
2559 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2560 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2562 /* Step 1: Reorder within Syllables */
2563 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari);
2564 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2565 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2566 *pcGlyphs = cCount;
2568 /* Step 2: Base Form application to syllables */
2569 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL);
2571 HeapFree(GetProcessHeap(),0,input);
2572 HeapFree(GetProcessHeap(),0,syllables);
2575 static int oriya_lex(WCHAR c)
2577 switch (c)
2579 case 0x0B24:
2580 case 0x0B28:
2581 case 0x0B2F:
2582 case 0x0B5F:
2583 case 0x0B71:
2584 case 0x0B33: return lex_Consonant;
2585 case 0x0B30: return lex_Ra;
2586 case 0x0B3C: return lex_Nukta;
2587 case 0x0B3F:
2588 case 0x0B56: return lex_Matra_above;
2589 case 0x0B3E:
2590 case 0x0B57:
2591 case 0x0B40: return lex_Matra_post;
2592 case 0x0B47: return lex_Matra_pre;
2593 case 0x0B4D: return lex_Halant;
2594 case 0x200C: return lex_ZWNJ;
2595 case 0x200D: return lex_ZWJ;
2596 default:
2597 if (c>=0x0B01 && c<=0x0B03) return lex_Modifier;
2598 else if (c>=0x0B05 && c<=0x0B14) return lex_Vowel;
2599 else if (c>=0x0B15 && c<=0x0B39) return lex_Consonant;
2600 else if (c>=0x0B41 && c<=0x0B44) return lex_Matra_below;
2601 else if (c>=0x0B48 && c<=0x0B4C) return lex_Composed_Vowel;
2602 else if (c>=0x0B5C && c<=0x0B5D) return lex_Consonant;
2603 else if (c>=0x0B60 && c<=0x0B61) return lex_Vowel;
2604 else if (c>=0x0B62 && c<=0x0B63) return lex_Matra_below;
2605 else return lex_Generic;
2609 static const VowelComponents Oriya_vowels[] = {
2610 {0x0B48, {0x0B47,0x0B56,0x0000}},
2611 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2612 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2613 {0x0000, {0x0000,0x0000,0x0000}}};
2615 static const ConsonantComponents Oriya_consonants[] = {
2616 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2617 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2618 {{0x0000,0x0000,0x0000}, 0x0000}};
2620 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2622 int cCount = cChars;
2623 WCHAR *input;
2624 IndicSyllable *syllables = NULL;
2625 int syllable_count = 0;
2627 if (*pcGlyphs != cChars)
2629 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2630 return;
2633 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2634 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2636 /* Step 1: Decompose Vowels and Compose Consonents */
2637 DecomposeVowels(hdc, input, &cCount, Oriya_vowels);
2638 ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2639 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2641 /* Step 2: Reorder within Syllables */
2642 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali);
2643 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2644 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2645 *pcGlyphs = cCount;
2647 /* Step 3: Base Form application to syllables */
2648 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL);
2650 HeapFree(GetProcessHeap(),0,input);
2651 HeapFree(GetProcessHeap(),0,syllables);
2654 static int tamil_lex(WCHAR c)
2656 switch (c)
2658 case 0x0BC0: return lex_Matra_above;
2659 case 0x0BCD: return lex_Halant;
2660 case 0x0BD7: return lex_Matra_post;
2661 case 0x200C: return lex_ZWNJ;
2662 case 0x200D: return lex_ZWJ;
2663 default:
2664 if (c>=0x0B95 && c<=0x0BB9) return lex_Consonant;
2665 else if (c>=0x0BBE && c<=0x0BBF) return lex_Matra_post;
2666 else if (c>=0x0BC1 && c<=0x0BC2) return lex_Matra_below;
2667 else if (c>=0x0BC6 && c<=0x0BC8) return lex_Matra_pre;
2668 else return lex_Generic;
2672 static const VowelComponents Tamil_vowels[] = {
2673 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2674 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2675 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2676 {0x0000, {0x0000,0x0000,0x0000}}};
2678 static const ConsonantComponents Tamil_consonants[] = {
2679 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2680 {{0x0000,0x0000,0x0000}, 0x0000}};
2682 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2684 int cCount = cChars;
2685 WCHAR *input;
2686 IndicSyllable *syllables = NULL;
2687 int syllable_count = 0;
2689 if (*pcGlyphs != cChars)
2691 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2692 return;
2695 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2696 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2698 /* Step 1: Decompose Vowels and Compose Consonents */
2699 DecomposeVowels(hdc, input, &cCount, Tamil_vowels);
2700 ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2701 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2703 /* Step 2: Reorder within Syllables */
2704 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali);
2705 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2706 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2707 *pcGlyphs = cCount;
2709 /* Step 3: Base Form application to syllables */
2710 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil);
2712 HeapFree(GetProcessHeap(),0,input);
2713 HeapFree(GetProcessHeap(),0,syllables);
2716 static int telugu_lex(WCHAR c)
2718 switch (c)
2720 case 0x0C4D: return lex_Halant;
2721 case 0x0C55: return lex_Matra_above;
2722 case 0x0C56: return lex_Matra_below;
2723 case 0x200C: return lex_ZWNJ;
2724 case 0x200D: return lex_ZWJ;
2725 default:
2726 if (c>=0x0C01 && c<=0x0C03) return lex_Modifier;
2727 else if (c>=0x0C05 && c<=0x0C14) return lex_Vowel;
2728 else if (c>=0x0C15 && c<=0x0C39) return lex_Consonant;
2729 else if (c>=0x0C3E && c<=0x0C40) return lex_Matra_above;
2730 else if (c>=0x0C41 && c<=0x0C42) return lex_Matra_post;
2731 else if (c>=0x0C43 && c<=0x0C44) return lex_Modifier;
2732 else if (c>=0x0C46 && c<=0x0C47) return lex_Matra_above;
2733 else if (c>=0x0C4A && c<=0x0C4C) return lex_Matra_above;
2734 else if (c>=0x0C58 && c<=0x0C59) return lex_Consonant;
2735 else if (c>=0x0C60 && c<=0x0C61) return lex_Vowel;
2736 else if (c>=0x0C62 && c<=0x0C63) return lex_Modifier;
2737 else return lex_Generic;
2741 static const VowelComponents Telugu_vowels[] = {
2742 {0x0C48, {0x0C46,0x0C56,0x0000}},
2743 {0x0000, {0x0000,0x0000,0x0000}}};
2745 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2747 int cCount = cChars;
2748 WCHAR *input;
2749 IndicSyllable *syllables = NULL;
2750 int syllable_count = 0;
2752 if (*pcGlyphs != cChars)
2754 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2755 return;
2758 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2759 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2761 /* Step 1: Decompose Vowels */
2762 DecomposeVowels(hdc, input, &cCount, Telugu_vowels);
2763 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2765 /* Step 2: Reorder within Syllables */
2766 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali);
2767 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2768 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2769 *pcGlyphs = cCount;
2771 /* Step 3: Base Form application to syllables */
2772 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu);
2774 HeapFree(GetProcessHeap(),0,input);
2775 HeapFree(GetProcessHeap(),0,syllables);
2778 static int kannada_lex(WCHAR c)
2780 switch (c)
2782 case 0x0CB0: return lex_Ra;
2783 case 0x0CBC: return lex_Nukta;
2784 case 0x0CBE: return lex_Matra_post;
2785 case 0x0CBF: return lex_Matra_above;
2786 case 0x0CC6: return lex_Matra_above;
2787 case 0x0CCC: return lex_Matra_above;
2788 case 0x0CCD: return lex_Halant;
2789 case 0x0CCE: return lex_Consonant;
2790 case 0x200C: return lex_ZWNJ;
2791 case 0x200D: return lex_ZWJ;
2792 default:
2793 if (c>=0x0C82 && c<=0x0C83) return lex_Modifier;
2794 else if (c>=0x0C85 && c<=0x0C94) return lex_Vowel;
2795 else if (c>=0x0C95 && c<=0x0CB9) return lex_Consonant;
2796 else if (c>=0x0CC1 && c<=0x0CC4) return lex_Matra_post;
2797 else if (c>=0x0CD5 && c<=0x0CD6) return lex_Modifier;
2798 else if (c>=0x0CE0 && c<=0x0CE1) return lex_Vowel;
2799 else if (c>=0x0CE2 && c<=0x0CE3) return lex_Matra_below;
2800 else return lex_Generic;
2804 static const VowelComponents Kannada_vowels[] = {
2805 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2806 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2807 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2808 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2809 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2810 {0x0000, {0x0000,0x0000,0x0000}}};
2812 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2814 int cCount = cChars;
2815 WCHAR *input;
2816 IndicSyllable *syllables = NULL;
2817 int syllable_count = 0;
2819 if (*pcGlyphs != cChars)
2821 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2822 return;
2825 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2826 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2828 /* Step 1: Decompose Vowels */
2829 DecomposeVowels(hdc, input, &cCount, Kannada_vowels);
2830 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2832 /* Step 2: Reorder within Syllables */
2833 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada);
2834 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2835 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2836 *pcGlyphs = cCount;
2838 /* Step 3: Base Form application to syllables */
2839 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu);
2841 HeapFree(GetProcessHeap(),0,input);
2842 HeapFree(GetProcessHeap(),0,syllables);
2845 static int malayalam_lex(WCHAR c)
2847 switch (c)
2849 case 0x0D35: return lex_Consonant;
2850 case 0x0D4D: return lex_Halant;
2851 case 0x0D57: return lex_Matra_post;
2852 case 0x200C: return lex_ZWNJ;
2853 case 0x200D: return lex_ZWJ;
2854 default:
2855 if (c>=0x0D02 && c<=0x0D03) return lex_Modifier;
2856 else if (c>=0x0D05 && c<=0x0D14) return lex_Vowel;
2857 else if (c>=0x0D15 && c<=0x0D39) return lex_Consonant;
2858 else if (c>=0x0D3E && c<=0x0D44) return lex_Matra_post;
2859 else if (c>=0x0D46 && c<=0x0D48) return lex_Matra_pre;
2860 else if (c>=0x0D60 && c<=0x0D61) return lex_Vowel;
2861 else if (c>=0x0D62 && c<=0x0D63) return lex_Matra_below;
2862 else return lex_Generic;
2866 static const VowelComponents Malayalam_vowels[] = {
2867 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2868 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2869 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2870 {0x0000, {0x0000,0x0000,0x0000}}};
2872 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2874 int cCount = cChars;
2875 WCHAR *input;
2876 IndicSyllable *syllables = NULL;
2877 int syllable_count = 0;
2879 if (*pcGlyphs != cChars)
2881 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2882 return;
2885 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2886 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2888 /* Step 1: Decompose Vowels */
2889 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels);
2890 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2892 /* Step 2: Reorder within Syllables */
2893 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari);
2894 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2895 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2896 *pcGlyphs = cCount;
2898 /* Step 3: Base Form application to syllables */
2899 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil);
2901 HeapFree(GetProcessHeap(),0,input);
2902 HeapFree(GetProcessHeap(),0,syllables);
2905 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)
2907 int i,k;
2909 for (i = 0; i < cGlyphs; i++)
2911 int char_index[20];
2912 int char_count = 0;
2914 for (k = 0; k < cChars; k++)
2916 if (pwLogClust[k] == i)
2918 char_index[char_count] = k;
2919 char_count++;
2923 if (char_count == 0)
2925 FIXME("No chars in this glyph? Must be an error\n");
2926 continue;
2929 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2931 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2932 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2934 else
2935 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2938 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2939 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2942 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 )
2944 int i,k;
2945 int initGlyph, finaGlyph;
2946 INT dirR, dirL;
2947 BYTE *spaces;
2949 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2950 memset(spaces,0,cGlyphs);
2952 if (!psa->fLogicalOrder && psa->fRTL)
2954 initGlyph = cGlyphs-1;
2955 finaGlyph = 0;
2956 dirR = 1;
2957 dirL = -1;
2959 else
2961 initGlyph = 0;
2962 finaGlyph = cGlyphs-1;
2963 dirR = -1;
2964 dirL = 1;
2967 for (i = 0; i < cGlyphs; i++)
2969 for (k = 0; k < cChars; k++)
2970 if (pwLogClust[k] == i)
2972 if (pwcChars[k] == 0x0020)
2973 spaces[i] = 1;
2977 for (i = 0; i < cGlyphs; i++)
2979 int char_index[20];
2980 int char_count = 0;
2981 BOOL isInit, isFinal;
2983 for (k = 0; k < cChars; k++)
2985 if (pwLogClust[k] == i)
2987 char_index[char_count] = k;
2988 char_count++;
2992 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2993 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2995 if (char_count == 0)
2997 FIXME("No chars in this glyph? Must be an error\n");
2998 continue;
3001 if (char_count == 1)
3003 if (pwcChars[char_index[0]] == 0x0020) /* space */
3005 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3006 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3008 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3009 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3010 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3012 if (!isInit && !isFinal)
3013 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3014 else if (isInit)
3015 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3016 else
3017 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3019 else if (!isInit)
3021 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3022 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3023 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3024 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3025 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3026 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3027 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3029 else
3030 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3032 else if (!isInit && !isFinal)
3033 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3034 else
3035 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3037 else if (char_count == 2)
3039 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3040 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3041 else if (!isInit)
3042 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3043 else
3044 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3046 else if (!isInit && !isFinal)
3047 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3048 else
3049 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3052 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3053 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3054 HeapFree(GetProcessHeap(),0,spaces);
3057 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 )
3059 int i,k;
3060 int finaGlyph;
3061 INT dirL;
3062 BYTE *spaces;
3064 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3065 memset(spaces,0,cGlyphs);
3067 if (!psa->fLogicalOrder && psa->fRTL)
3069 finaGlyph = 0;
3070 dirL = -1;
3072 else
3074 finaGlyph = cGlyphs-1;
3075 dirL = 1;
3078 for (i = 0; i < cGlyphs; i++)
3080 for (k = 0; k < cChars; k++)
3081 if (pwLogClust[k] == i)
3083 if (pwcChars[k] == 0x0020)
3084 spaces[i] = 1;
3088 for (i = 0; i < cGlyphs; i++)
3090 int char_index[20];
3091 int char_count = 0;
3093 for (k = 0; k < cChars; k++)
3095 if (pwLogClust[k] == i)
3097 char_index[char_count] = k;
3098 char_count++;
3102 if (char_count == 0)
3104 FIXME("No chars in this glyph? Must be an error\n");
3105 continue;
3108 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3110 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3111 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3113 else if (i == finaGlyph)
3114 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3115 else
3116 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3119 HeapFree(GetProcessHeap(),0,spaces);
3120 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3121 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3123 /* Do not allow justification between marks and their base */
3124 for (i = 0; i < cGlyphs; i++)
3126 if (!pGlyphProp[i].sva.fClusterStart)
3127 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3131 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)
3133 int i,k;
3135 for (i = 0; i < cGlyphs; i++)
3137 int char_index[20];
3138 int char_count = 0;
3140 for (k = 0; k < cChars; k++)
3142 if (pwLogClust[k] == i)
3144 char_index[char_count] = k;
3145 char_count++;
3149 if (char_count == 0)
3151 FIXME("No chars in this glyph? Must be an error\n");
3152 continue;
3155 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3157 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3158 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3160 else
3161 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3163 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3164 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3167 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)
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_BLANK;
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);
3202 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3203 for (i = 0; i < cGlyphs; i++)
3205 if (!pGlyphProp[i].sva.fClusterStart)
3207 pGlyphProp[i].sva.fDiacritic = 0;
3208 pGlyphProp[i].sva.fZeroWidth = 0;
3213 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)
3215 int i,k;
3217 for (i = 0; i < cGlyphs; i++)
3219 int char_index[20];
3220 int char_count = 0;
3222 for (k = 0; k < cChars; k++)
3224 if (pwLogClust[k] == i)
3226 char_index[char_count] = k;
3227 char_count++;
3231 if (char_count == 0)
3233 FIXME("No chars in this glyph? Must be an error\n");
3234 continue;
3237 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3239 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3240 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3242 else
3243 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3245 pGlyphProp[i].sva.fClusterStart = 0;
3246 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3247 switch (lexical(pwcChars[char_index[k]]))
3249 case lex_Matra_pre:
3250 case lex_Matra_post:
3251 case lex_Matra_above:
3252 case lex_Matra_below:
3253 case lex_Modifier:
3254 break;
3255 default:
3256 pGlyphProp[i].sva.fClusterStart = 1;
3257 break;
3260 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3263 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 )
3265 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3268 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 )
3270 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3273 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 )
3275 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3278 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 )
3280 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3283 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 )
3285 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3288 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 )
3290 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3293 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 )
3295 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3298 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 )
3300 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3303 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 )
3305 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3308 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)
3310 if (ShapingData[psa->eScript].charGlyphPropProc)
3311 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3312 else
3313 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3316 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3318 if (ShapingData[psa->eScript].contextProc)
3319 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3322 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)
3324 int i;
3325 INT dirL;
3327 if (!rpRangeProperties)
3328 return;
3330 if (!psc->GSUB_Table)
3331 psc->GSUB_Table = load_gsub_table(hdc);
3333 if (!psc->GSUB_Table)
3334 return;
3336 if (!psa->fLogicalOrder && psa->fRTL)
3337 dirL = -1;
3338 else
3339 dirL = 1;
3341 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3343 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3344 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3348 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3350 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3351 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3353 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3356 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3358 const GSUB_Feature *feature;
3359 int i;
3361 if (!ShapingData[psa->eScript].requiredFeatures)
3362 return S_OK;
3364 if (!psc->GSUB_Table)
3365 psc->GSUB_Table = load_gsub_table(hdc);
3367 /* we need to have at least one of the required features */
3368 i = 0;
3369 while (ShapingData[psa->eScript].requiredFeatures[i])
3371 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3372 if (feature)
3373 return S_OK;
3374 i++;
3377 return USP_E_SCRIPT_NOT_IN_FONT;