usp10: Condense duplicate Indic feature sets.
[wine.git] / dlls / usp10 / shape.c
blob63a9a2f04f68193ba54fe7d345a9327797837f03
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 /* the orders of joined_forms and contextual_features need to line up */
313 static const char* contextual_features[] =
315 "isol",
316 "fina",
317 "init",
318 "medi",
319 /* Syriac Alaph */
320 "med2",
321 "fin2",
322 "fin3"
325 static OPENTYPE_FEATURE_RECORD standard_features[] =
327 { MS_MAKE_TAG('l','i','g','a'), 1},
328 { MS_MAKE_TAG('c','l','i','g'), 1},
331 static OPENTYPE_FEATURE_RECORD arabic_features[] =
333 { MS_MAKE_TAG('r','l','i','g'), 1},
334 { MS_MAKE_TAG('c','a','l','t'), 1},
335 { MS_MAKE_TAG('l','i','g','a'), 1},
336 { MS_MAKE_TAG('d','l','i','g'), 1},
337 { MS_MAKE_TAG('c','s','w','h'), 1},
338 { MS_MAKE_TAG('m','s','e','t'), 1},
341 static const char* required_arabic_features[] =
343 "fina",
344 "init",
345 "medi",
346 "rlig",
347 NULL
350 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
352 { MS_MAKE_TAG('d','l','i','g'), 1},
355 static OPENTYPE_FEATURE_RECORD syriac_features[] =
357 { MS_MAKE_TAG('r','l','i','g'), 1},
358 { MS_MAKE_TAG('c','a','l','t'), 1},
359 { MS_MAKE_TAG('l','i','g','a'), 1},
360 { MS_MAKE_TAG('d','l','i','g'), 1},
363 static const char* required_syriac_features[] =
365 "fina",
366 "fin2",
367 "fin3",
368 "init",
369 "medi",
370 "med2",
371 "rlig",
372 NULL
375 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
377 /* Presentation forms */
378 { MS_MAKE_TAG('b','l','w','s'), 1},
379 { MS_MAKE_TAG('a','b','v','s'), 1},
380 { MS_MAKE_TAG('p','s','t','s'), 1},
383 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
385 { MS_MAKE_TAG('a','b','v','s'), 1},
386 { MS_MAKE_TAG('b','l','w','s'), 1},
389 static OPENTYPE_FEATURE_RECORD thai_features[] =
391 { MS_MAKE_TAG('c','c','m','p'), 1},
394 static const char* required_lao_features[] =
396 "ccmp",
397 NULL
400 static const char* required_devanagari_features[] =
402 "nukt",
403 "akhn",
404 "rphf",
405 "blwf",
406 "half",
407 "vatu",
408 "pres",
409 "abvs",
410 "blws",
411 "psts",
412 "haln",
413 NULL
416 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
418 { MS_MAKE_TAG('p','r','e','s'), 1},
419 { MS_MAKE_TAG('a','b','v','s'), 1},
420 { MS_MAKE_TAG('b','l','w','s'), 1},
421 { MS_MAKE_TAG('p','s','t','s'), 1},
422 { MS_MAKE_TAG('h','a','l','n'), 1},
423 { MS_MAKE_TAG('c','a','l','t'), 1},
426 static const char* required_bengali_features[] =
428 "nukt",
429 "akhn",
430 "rphf",
431 "blwf",
432 "half",
433 "vatu",
434 "pstf",
435 "init",
436 "abvs",
437 "blws",
438 "psts",
439 "haln",
440 NULL
443 static const char* required_gurmukhi_features[] =
445 "nukt",
446 "akhn",
447 "rphf",
448 "blwf",
449 "half",
450 "pstf",
451 "vatu",
452 "cjct",
453 "pres",
454 "abvs",
455 "blws",
456 "psts",
457 "haln",
458 "calt",
459 NULL
462 static const char* required_oriya_features[] =
464 "nukt",
465 "akhn",
466 "rphf",
467 "blwf",
468 "pstf",
469 "cjct",
470 "pres",
471 "abvs",
472 "blws",
473 "psts",
474 "haln",
475 "calt",
476 NULL
479 static const char* required_tamil_features[] =
481 "nukt",
482 "akhn",
483 "rphf",
484 "pref",
485 "half",
486 "pres",
487 "abvs",
488 "blws",
489 "psts",
490 "haln",
491 "calt",
492 NULL
495 static const char* required_telugu_features[] =
497 "nukt",
498 "akhn",
499 "rphf",
500 "pref",
501 "half",
502 "pstf",
503 "cjct",
504 "pres",
505 "abvs",
506 "blws",
507 "psts",
508 "haln",
509 "calt",
510 NULL
513 typedef struct ScriptShapeDataTag {
514 TEXTRANGE_PROPERTIES defaultTextRange;
515 const char** requiredFeatures;
516 CHAR otTag[5];
517 CHAR newOtTag[5];
518 ContextualShapingProc contextProc;
519 ShapeCharGlyphPropProc charGlyphPropProc;
520 } ScriptShapeData;
522 /* in order of scripts */
523 static const ScriptShapeData ShapingData[] =
525 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
526 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
527 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
528 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
529 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
530 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
531 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
532 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
533 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
534 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
535 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
536 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
537 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
538 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
539 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
540 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
541 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
542 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
543 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
544 {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
545 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
546 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
547 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
548 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
549 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
550 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
551 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
552 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
553 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
554 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
555 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
556 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
557 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
558 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
559 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
560 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
561 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
562 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
563 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
564 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
565 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
566 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
567 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
570 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
572 const GSUB_CoverageFormat1* cf1;
574 cf1 = table;
576 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
578 int count = GET_BE_WORD(cf1->GlyphCount);
579 int i;
580 TRACE("Coverage Format 1, %i glyphs\n",count);
581 for (i = 0; i < count; i++)
582 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
583 return i;
584 return -1;
586 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
588 const GSUB_CoverageFormat2* cf2;
589 int i;
590 int count;
591 cf2 = (const GSUB_CoverageFormat2*)cf1;
593 count = GET_BE_WORD(cf2->RangeCount);
594 TRACE("Coverage Format 2, %i ranges\n",count);
595 for (i = 0; i < count; i++)
597 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
598 return -1;
599 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
600 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
602 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
603 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
606 return -1;
608 else
609 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
611 return -1;
614 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
616 const GSUB_ScriptList *script;
617 const GSUB_Script *deflt = NULL;
618 int i;
619 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
621 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
622 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
624 const GSUB_Script *scr;
625 int offset;
627 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
628 scr = (const GSUB_Script*)((const BYTE*)script + offset);
630 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
631 return scr;
632 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
633 deflt = scr;
635 return deflt;
638 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
640 int i;
641 int offset;
642 const GSUB_LangSys *Lang;
644 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
646 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
648 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
649 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
651 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
652 return Lang;
654 offset = GET_BE_WORD(script->DefaultLangSys);
655 if (offset)
657 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
658 return Lang;
660 return NULL;
663 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
665 int i;
666 const GSUB_FeatureList *feature;
667 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
669 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
670 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
672 int index = GET_BE_WORD(lang->FeatureIndex[i]);
673 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
675 const GSUB_Feature *feat;
676 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
677 return feat;
680 return NULL;
683 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
685 int j;
686 TRACE("Single Substitution Subtable\n");
688 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
690 int offset;
691 const GSUB_SingleSubstFormat1 *ssf1;
692 offset = GET_BE_WORD(look->SubTable[j]);
693 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
694 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
696 int offset = GET_BE_WORD(ssf1->Coverage);
697 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
698 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
700 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
701 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
702 TRACE(" 0x%x\n",glyphs[glyph_index]);
703 return glyph_index + 1;
706 else
708 const GSUB_SingleSubstFormat2 *ssf2;
709 INT index;
710 INT offset;
712 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
713 offset = GET_BE_WORD(ssf1->Coverage);
714 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
715 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
716 TRACE(" Coverage index %i\n",index);
717 if (index != -1)
719 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
720 return GSUB_E_NOGLYPH;
722 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
723 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
724 TRACE("0x%x\n",glyphs[glyph_index]);
725 return glyph_index + 1;
729 return GSUB_E_NOGLYPH;
732 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
734 int j;
735 TRACE("Alternate Substitution Subtable\n");
737 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
739 int offset;
740 const GSUB_AlternateSubstFormat1 *asf1;
741 INT index;
743 offset = GET_BE_WORD(look->SubTable[j]);
744 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
745 offset = GET_BE_WORD(asf1->Coverage);
747 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
748 if (index != -1)
750 const GSUB_AlternateSet *as;
751 offset = GET_BE_WORD(asf1->AlternateSet[index]);
752 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
753 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
754 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
755 return GSUB_E_NOGLYPH;
757 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
758 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
759 TRACE(" 0x%x\n",glyphs[glyph_index]);
760 return glyph_index + 1;
763 return GSUB_E_NOGLYPH;
766 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
768 int j;
770 TRACE("Ligature Substitution Subtable\n");
771 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
773 const GSUB_LigatureSubstFormat1 *lsf1;
774 int offset,index;
776 offset = GET_BE_WORD(look->SubTable[j]);
777 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
778 offset = GET_BE_WORD(lsf1->Coverage);
779 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
780 TRACE(" Coverage index %i\n",index);
781 if (index != -1)
783 const GSUB_LigatureSet *ls;
784 int k, count;
786 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
787 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
788 count = GET_BE_WORD(ls->LigatureCount);
789 TRACE(" LigatureSet has %i members\n",count);
790 for (k = 0; k < count; k++)
792 const GSUB_Ligature *lig;
793 int CompCount,l,CompIndex;
795 offset = GET_BE_WORD(ls->Ligature[k]);
796 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
797 CompCount = GET_BE_WORD(lig->CompCount) - 1;
798 CompIndex = glyph_index+write_dir;
799 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
801 int CompGlyph;
802 CompGlyph = GET_BE_WORD(lig->Component[l]);
803 if (CompGlyph != glyphs[CompIndex])
804 break;
805 CompIndex += write_dir;
807 if (l == CompCount)
809 int replaceIdx = glyph_index;
810 if (write_dir < 0)
811 replaceIdx = glyph_index - CompCount;
813 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
814 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
815 TRACE("0x%x\n",glyphs[replaceIdx]);
816 if (CompCount > 0)
818 int j;
819 for (j = replaceIdx + 1; j < *glyph_count; j++)
820 glyphs[j] =glyphs[j+CompCount];
821 *glyph_count = *glyph_count - CompCount;
823 return replaceIdx + 1;
828 return GSUB_E_NOGLYPH;
831 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
833 int j;
834 BOOL done = FALSE;
836 TRACE("Chaining Contextual Substitution Subtable\n");
837 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
839 const GSUB_ChainContextSubstFormat1 *ccsf1;
840 int offset;
841 int dirLookahead = write_dir;
842 int dirBacktrack = -1 * write_dir;
844 offset = GET_BE_WORD(look->SubTable[j]);
845 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
846 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
848 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
849 continue;
851 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
853 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
854 continue;
856 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
858 int k;
859 int indexGlyphs;
860 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
861 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
862 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
863 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
864 int newIndex = glyph_index;
866 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
868 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
870 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
872 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
873 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
874 break;
876 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
877 continue;
878 TRACE("Matched Backtrack\n");
880 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
882 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
883 for (k = 0; k < indexGlyphs; k++)
885 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
886 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
887 break;
889 if (k != indexGlyphs)
890 continue;
891 TRACE("Matched IndexGlyphs\n");
893 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
895 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
897 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
898 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
899 break;
901 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
902 continue;
903 TRACE("Matched LookAhead\n");
905 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
907 if (GET_BE_WORD(ccsf3_4->SubstCount))
909 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
911 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
912 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
914 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
915 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
916 if (newIndex == -1)
918 ERR("Chain failed to generate a glyph\n");
919 continue;
922 return newIndex;
924 else return GSUB_E_NOGLYPH;
927 return -1;
930 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
932 int offset;
933 const GSUB_LookupTable *look;
935 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
936 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
937 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
938 switch(GET_BE_WORD(look->LookupType))
940 case 1:
941 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
942 case 3:
943 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
944 case 4:
945 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
946 case 6:
947 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
948 default:
949 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
951 return GSUB_E_NOGLYPH;
954 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
956 int i;
957 int out_index = GSUB_E_NOGLYPH;
958 const GSUB_LookupList *lookup;
960 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
962 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
963 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
965 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
966 if (out_index != GSUB_E_NOGLYPH)
967 break;
969 if (out_index == GSUB_E_NOGLYPH)
970 TRACE("lookups found no glyphs\n");
971 else
973 int out2;
974 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
975 if (out2!=GSUB_E_NOGLYPH)
976 out_index = out2;
978 return out_index;
981 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
983 UINT charset;
985 if (psc->userScript != 0)
987 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
988 return ShapingData[psa->eScript].newOtTag;
989 else
990 return (char*)&psc->userScript;
993 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
994 return ShapingData[psa->eScript].newOtTag;
996 if (ShapingData[psa->eScript].otTag[0] != 0)
997 return ShapingData[psa->eScript].otTag;
1000 * fall back to the font charset
1002 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1003 switch (charset)
1005 case ANSI_CHARSET: return "latn";
1006 case BALTIC_CHARSET: return "latn"; /* ?? */
1007 case CHINESEBIG5_CHARSET: return "hani";
1008 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1009 case GB2312_CHARSET: return "hani";
1010 case GREEK_CHARSET: return "grek";
1011 case HANGUL_CHARSET: return "hang";
1012 case RUSSIAN_CHARSET: return "cyrl";
1013 case SHIFTJIS_CHARSET: return "kana";
1014 case TURKISH_CHARSET: return "latn"; /* ?? */
1015 case VIETNAMESE_CHARSET: return "latn";
1016 case JOHAB_CHARSET: return "latn"; /* ?? */
1017 case ARABIC_CHARSET: return "arab";
1018 case HEBREW_CHARSET: return "hebr";
1019 case THAI_CHARSET: return "thai";
1020 default: return "latn";
1024 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1026 const GSUB_Feature *feature;
1027 int i;
1029 for (i = 0; i < psc->feature_count; i++)
1030 if (strncmp(psc->features[i].tag,feat,4)==0)
1031 return psc->features[i].feature;
1033 feature = NULL;
1035 if (psc->GSUB_Table)
1037 const GSUB_Script *script;
1038 const GSUB_LangSys *language;
1039 int attempt = 2;
1043 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1044 attempt--;
1045 if (script)
1047 if (psc->userLang != 0)
1048 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1049 else
1050 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1051 if (language)
1052 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1054 } while(attempt && !feature);
1056 /* try in the default (latin) table */
1057 if (!feature)
1059 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1060 if (script)
1062 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1063 if (language)
1064 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1069 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1071 psc->feature_count++;
1073 if (psc->features)
1074 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1075 else
1076 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1078 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1079 psc->features[psc->feature_count - 1].feature = feature;
1080 return feature;
1083 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)
1085 const GSUB_Feature *feature;
1087 feature = load_GSUB_feature(hdc, psa, psc, feat);
1088 if (!feature)
1089 return GSUB_E_NOFEATURE;
1091 TRACE("applying feature %s\n",feat);
1092 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1095 static VOID *load_gsub_table(HDC hdc)
1097 VOID* GSUB_Table = NULL;
1098 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1099 if (length != GDI_ERROR)
1101 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1102 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1103 TRACE("Loaded GSUB table of %i bytes\n",length);
1105 return GSUB_Table;
1108 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)
1110 WORD *glyphs;
1111 INT glyph_count = count;
1112 INT rc;
1114 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1115 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1116 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1117 if (rc > GSUB_E_NOGLYPH)
1118 rc = count - glyph_count;
1119 else
1120 rc = 0;
1122 HeapFree(GetProcessHeap(),0,glyphs);
1123 return rc;
1126 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1128 int offset;
1129 WORD class = 0;
1130 const GDEF_ClassDefFormat1 *cf1;
1132 if (!header)
1133 return 0;
1135 offset = GET_BE_WORD(header->GlyphClassDef);
1136 if (!offset)
1137 return 0;
1139 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1140 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1142 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1144 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1145 if (index < GET_BE_WORD(cf1->GlyphCount))
1146 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1149 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1151 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1152 int i, top;
1153 top = GET_BE_WORD(cf2->ClassRangeCount);
1154 for (i = 0; i < top; i++)
1156 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1157 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1159 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1160 break;
1164 else
1165 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1167 return class;
1170 static VOID *load_gdef_table(HDC hdc)
1172 VOID* GDEF_Table = NULL;
1173 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1174 if (length != GDI_ERROR)
1176 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1177 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1178 TRACE("Loaded GDEF table of %i bytes\n",length);
1180 return GDEF_Table;
1183 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1185 int i;
1187 if (!psc->GDEF_Table)
1188 psc->GDEF_Table = load_gdef_table(hdc);
1190 for (i = 0; i < cGlyphs; i++)
1192 WORD class;
1194 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1196 switch (class)
1198 case 0:
1199 case BaseGlyph:
1200 pGlyphProp[i].sva.fClusterStart = 1;
1201 pGlyphProp[i].sva.fDiacritic = 0;
1202 pGlyphProp[i].sva.fZeroWidth = 0;
1203 break;
1204 case LigatureGlyph:
1205 pGlyphProp[i].sva.fClusterStart = 1;
1206 pGlyphProp[i].sva.fDiacritic = 0;
1207 pGlyphProp[i].sva.fZeroWidth = 0;
1208 break;
1209 case MarkGlyph:
1210 pGlyphProp[i].sva.fClusterStart = 0;
1211 pGlyphProp[i].sva.fDiacritic = 1;
1212 pGlyphProp[i].sva.fZeroWidth = 1;
1213 break;
1214 case ComponentGlyph:
1215 pGlyphProp[i].sva.fClusterStart = 0;
1216 pGlyphProp[i].sva.fDiacritic = 0;
1217 pGlyphProp[i].sva.fZeroWidth = 0;
1218 break;
1219 default:
1220 ERR("Unknown glyph class %i\n",class);
1221 pGlyphProp[i].sva.fClusterStart = 1;
1222 pGlyphProp[i].sva.fDiacritic = 0;
1223 pGlyphProp[i].sva.fZeroWidth = 0;
1228 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1230 int i;
1232 for (i = 0; i < cGlyphs; i++)
1234 if (!pGlyphProp[i].sva.fClusterStart)
1236 int j;
1237 for (j = 0; j < cChars; j++)
1239 if (pwLogClust[j] == i)
1241 int k = j;
1242 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1243 k-=1;
1244 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1245 pwLogClust[j] = pwLogClust[k];
1252 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1254 if (changeCount == 0)
1255 return;
1256 else
1258 int i;
1259 int target_glyph = nextIndex - 1;
1260 int target_index = -1;
1261 int replacing_glyph = -1;
1262 int changed = 0;
1264 if (write_dir > 0)
1265 for (i = 0; i < chars; i++)
1267 if (pwLogClust[i] == target_glyph)
1269 target_index = i;
1270 break;
1273 else
1274 for (i = chars - 1; i >= 0; i--)
1276 if (pwLogClust[i] == target_glyph)
1278 target_index = i;
1279 break;
1282 if (target_index == -1)
1284 ERR("Unable to find target glyph\n");
1285 return;
1288 if (changeCount < 0)
1290 /* merge glyphs */
1291 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1293 if (pwLogClust[i] == target_glyph)
1294 continue;
1295 if(pwLogClust[i] == replacing_glyph)
1296 pwLogClust[i] = target_glyph;
1297 else
1299 changed--;
1300 if (changed >= changeCount)
1302 replacing_glyph = pwLogClust[i];
1303 pwLogClust[i] = target_glyph;
1305 else
1306 break;
1311 /* renumber trailing indexes*/
1312 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1314 if (pwLogClust[i] != target_glyph)
1315 pwLogClust[i] += changeCount;
1320 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 )
1322 int i;
1324 if (psc->GSUB_Table)
1326 const GSUB_Feature *feature;
1328 feature = load_GSUB_feature(hdc, psa, psc, feat);
1329 if (!feature)
1330 return GSUB_E_NOFEATURE;
1332 i = 0;
1333 TRACE("applying feature %s\n",debugstr_an(feat,4));
1334 while(i < *pcGlyphs)
1336 INT nextIndex;
1337 INT prevCount = *pcGlyphs;
1338 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1339 if (nextIndex > GSUB_E_NOGLYPH)
1341 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1342 i = nextIndex;
1344 else
1345 i++;
1347 return *pcGlyphs;
1349 return GSUB_E_NOFEATURE;
1352 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1354 if (i + delta < 0)
1355 return 0;
1356 if ( i+ delta >= cchLen)
1357 return 0;
1359 i += delta;
1361 return chars[i];
1364 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1366 if (i + delta < 0)
1368 if (psa->fLinkBefore)
1369 return jtR;
1370 else
1371 return jtU;
1373 if ( i+ delta >= cchLen)
1375 if (psa->fLinkAfter)
1376 return jtL;
1377 else
1378 return jtU;
1381 i += delta;
1383 if (context_type[i] == jtT)
1384 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1385 else
1386 return context_type[i];
1389 static inline BOOL right_join_causing(CHAR joining_type)
1391 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1394 static inline BOOL left_join_causing(CHAR joining_type)
1396 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1399 static inline BOOL word_break_causing(WCHAR chr)
1401 /* we are working within a string of characters already guareented to
1402 be within one script, Syriac, so we do not worry about any characers
1403 other than the space character outside of that range */
1404 return (chr == 0 || chr == 0x20 );
1408 * ContextualShape_Arabic
1410 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1412 CHAR *context_type;
1413 INT *context_shape;
1414 INT dirR, dirL;
1415 int i;
1417 if (*pcGlyphs != cChars)
1419 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1420 return;
1423 if (!psa->fLogicalOrder && psa->fRTL)
1425 dirR = 1;
1426 dirL = -1;
1428 else
1430 dirR = -1;
1431 dirL = 1;
1434 if (!psc->GSUB_Table)
1435 psc->GSUB_Table = load_gsub_table(hdc);
1437 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1438 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1440 for (i = 0; i < cChars; i++)
1441 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1443 for (i = 0; i < cChars; i++)
1445 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1446 context_shape[i] = Xr;
1447 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1448 context_shape[i] = Xl;
1449 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)))
1450 context_shape[i] = Xm;
1451 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1452 context_shape[i] = Xr;
1453 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1454 context_shape[i] = Xl;
1455 else
1456 context_shape[i] = Xn;
1459 /* Contextual Shaping */
1460 i = 0;
1461 while(i < *pcGlyphs)
1463 BOOL shaped = FALSE;
1465 if (psc->GSUB_Table)
1467 INT nextIndex;
1468 INT prevCount = *pcGlyphs;
1469 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1470 if (nextIndex > GSUB_E_NOGLYPH)
1472 i = nextIndex;
1473 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1475 shaped = (nextIndex > GSUB_E_NOGLYPH);
1478 if (!shaped)
1480 WORD newGlyph = pwOutGlyphs[i];
1481 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1483 /* fall back to presentation form B */
1484 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1485 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1486 pwOutGlyphs[i] = newGlyph;
1488 i++;
1492 HeapFree(GetProcessHeap(),0,context_shape);
1493 HeapFree(GetProcessHeap(),0,context_type);
1497 * ContextualShape_Syriac
1500 #define ALAPH 0x710
1501 #define DALATH 0x715
1502 #define RISH 0x72A
1504 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1506 CHAR *context_type;
1507 INT *context_shape;
1508 INT dirR, dirL;
1509 int i;
1511 if (*pcGlyphs != cChars)
1513 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1514 return;
1517 if (!psa->fLogicalOrder && psa->fRTL)
1519 dirR = 1;
1520 dirL = -1;
1522 else
1524 dirR = -1;
1525 dirL = 1;
1528 if (!psc->GSUB_Table)
1529 psc->GSUB_Table = load_gsub_table(hdc);
1531 if (!psc->GSUB_Table)
1532 return;
1534 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1535 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1537 for (i = 0; i < cChars; i++)
1538 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1540 for (i = 0; i < cChars; i++)
1542 if (pwcChars[i] == ALAPH)
1544 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1546 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1547 context_shape[i] = Afj;
1548 else if ( rchar != DALATH && rchar != RISH &&
1549 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1550 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1551 context_shape[i] = Afn;
1552 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1553 context_shape[i] = Afx;
1554 else
1555 context_shape[i] = Xn;
1557 else if (context_type[i] == jtR &&
1558 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1559 context_shape[i] = Xr;
1560 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1561 context_shape[i] = Xl;
1562 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)))
1563 context_shape[i] = Xm;
1564 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1565 context_shape[i] = Xr;
1566 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1567 context_shape[i] = Xl;
1568 else
1569 context_shape[i] = Xn;
1572 /* Contextual Shaping */
1573 i = 0;
1574 while(i < *pcGlyphs)
1576 INT nextIndex;
1577 INT prevCount = *pcGlyphs;
1578 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1579 if (nextIndex > GSUB_E_NOGLYPH)
1581 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1582 i = nextIndex;
1584 else
1585 i++;
1588 HeapFree(GetProcessHeap(),0,context_shape);
1589 HeapFree(GetProcessHeap(),0,context_type);
1593 * ContextualShape_Phags_pa
1596 #define phags_pa_CANDRABINDU 0xA873
1597 #define phags_pa_START 0xA840
1598 #define phags_pa_END 0xA87F
1600 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1602 INT *context_shape;
1603 INT dirR, dirL;
1604 int i;
1606 if (*pcGlyphs != cChars)
1608 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1609 return;
1612 if (!psa->fLogicalOrder && psa->fRTL)
1614 dirR = 1;
1615 dirL = -1;
1617 else
1619 dirR = -1;
1620 dirL = 1;
1623 if (!psc->GSUB_Table)
1624 psc->GSUB_Table = load_gsub_table(hdc);
1626 if (!psc->GSUB_Table)
1627 return;
1629 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1631 for (i = 0; i < cChars; i++)
1633 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1635 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1636 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1637 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1638 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1640 if (jrchar && jlchar)
1641 context_shape[i] = Xm;
1642 else if (jrchar)
1643 context_shape[i] = Xr;
1644 else if (jlchar)
1645 context_shape[i] = Xl;
1646 else
1647 context_shape[i] = Xn;
1649 else
1650 context_shape[i] = -1;
1653 /* Contextual Shaping */
1654 i = 0;
1655 while(i < *pcGlyphs)
1657 if (context_shape[i] >= 0)
1659 INT nextIndex;
1660 INT prevCount = *pcGlyphs;
1661 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1662 if (nextIndex > GSUB_E_NOGLYPH)
1664 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1665 i = nextIndex;
1667 else
1668 i++;
1670 else
1671 i++;
1674 HeapFree(GetProcessHeap(),0,context_shape);
1677 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1679 int i;
1681 /* Replace */
1682 pwOutChars[cWalk] = replacements[0];
1683 cWalk=cWalk+1;
1685 /* Insert */
1686 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1688 int j;
1689 for (j = *pcChars; j > cWalk; j--)
1690 pwOutChars[j] = pwOutChars[j-1];
1691 *pcChars= *pcChars+1;
1692 pwOutChars[cWalk] = replacements[i];
1693 cWalk = cWalk+1;
1697 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1699 int i;
1700 int cWalk;
1702 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1704 for (i = 0; vowels[i].base != 0x0; i++)
1706 if (pwOutChars[cWalk] == vowels[i].base)
1708 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1709 if (vowels[i].parts[1]) cWalk++;
1710 if (vowels[i].parts[2]) cWalk++;
1711 break;
1717 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1719 int i;
1720 int cWalk;
1722 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1724 for (i = 0; consonants[i].output!= 0x0; i++)
1726 int j;
1727 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1728 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1729 break;
1731 if (consonants[i].parts[j]==0x0) /* matched all */
1733 int k;
1734 j--;
1735 pwOutChars[cWalk] = consonants[i].output;
1736 for(k = cWalk+1; k < *pcChars - j; k++)
1737 pwOutChars[k] = pwOutChars[k+j];
1738 *pcChars = *pcChars - j;
1739 break;
1742 cWalk++;
1746 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1748 if (s->ralf >= 0)
1750 int j;
1751 WORD Ra = pwChar[s->start];
1752 WORD H = pwChar[s->start+1];
1754 TRACE("Doing reorder of Ra to %i\n",s->base);
1755 for (j = s->start; j < s->base-1; j++)
1756 pwChar[j] = pwChar[j+2];
1757 pwChar[s->base-1] = Ra;
1758 pwChar[s->base] = H;
1760 s->ralf = s->base-1;
1761 s->base -= 2;
1765 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1767 if (s->ralf >= 0)
1769 int j,loc;
1770 WORD Ra = pwChar[s->start];
1771 WORD H = pwChar[s->start+1];
1772 for (loc = s->end; loc > s->base; loc--)
1773 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1774 break;
1776 TRACE("Doing reorder of Ra to %i\n",loc);
1777 for (j = s->start; j < loc-1; j++)
1778 pwChar[j] = pwChar[j+2];
1779 pwChar[loc-1] = Ra;
1780 pwChar[loc] = H;
1782 s->ralf = loc-1;
1783 s->base -= 2;
1787 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1789 if (s->ralf >= 0)
1791 int j;
1792 WORD Ra = pwChar[s->start];
1793 WORD H = pwChar[s->start+1];
1795 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1796 for (j = s->start; j < s->end-1; j++)
1797 pwChar[j] = pwChar[j+2];
1798 pwChar[s->end-1] = Ra;
1799 pwChar[s->end] = H;
1801 s->ralf = s->end-1;
1802 s->base -= 2;
1806 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1808 int i;
1810 /* reorder Matras */
1811 if (s->end > s->base)
1813 for (i = 1; i <= s->end-s->base; i++)
1815 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1817 int j;
1818 WCHAR c = pwChar[s->base+i];
1819 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1820 for (j = s->base+i; j > s->base; j--)
1821 pwChar[j] = pwChar[j-1];
1822 pwChar[s->base] = c;
1824 if (s->ralf >= s->base) s->ralf++;
1825 s->base ++;
1831 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1833 int i;
1835 /* reorder Matras */
1836 if (s->end > s->base)
1838 for (i = 1; i <= s->end-s->base; i++)
1840 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1842 int j;
1843 WCHAR c = pwChar[s->base+i];
1844 TRACE("Doing reorder of %x to %i\n",c,s->start);
1845 for (j = s->base+i; j > s->start; j--)
1846 pwChar[j] = pwChar[j-1];
1847 pwChar[s->start] = c;
1849 if (s->ralf >= 0) s->ralf++;
1850 s->base ++;
1856 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1858 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1859 if (s->start == s->base && s->base == s->end) return;
1860 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1862 Reorder_Ra_follows_base(pwChar, s, lexical);
1863 Reorder_Matra_precede_base(pwChar, s, lexical);
1866 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1868 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1869 if (s->start == s->base && s->base == s->end) return;
1870 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1872 Reorder_Ra_follows_matra(pwChar, s, lexical);
1873 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1876 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1878 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1879 if (s->start == s->base && s->base == s->end) return;
1880 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1882 Reorder_Ra_follows_base(pwChar, s, lexical);
1883 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1886 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1888 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1889 if (s->start == s->base && s->base == s->end) return;
1890 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1892 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1893 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1896 static void Reorder_Like_Malayalam(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1898 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1899 if (s->start == s->base && s->base == s->end) return;
1900 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1902 Reorder_Ra_follows_matra(pwChar, s, lexical);
1903 Reorder_Matra_precede_base(pwChar, s, lexical);
1906 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1908 if (shift == 0)
1909 return;
1911 if (glyph_index->start > index)
1912 glyph_index->start += shift;
1913 if (glyph_index->base > index)
1914 glyph_index->base+= shift;
1915 if (glyph_index->end > index)
1916 glyph_index->end+= shift;
1917 if (glyph_index->ralf > index)
1918 glyph_index->ralf+= shift;
1921 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 )
1923 int index = glyph_index->start;
1925 if (!feature)
1926 return;
1928 while(index <= glyph_index->end)
1930 INT nextIndex;
1931 INT prevCount = *pcGlyphs;
1932 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1933 if (nextIndex > GSUB_E_NOGLYPH)
1935 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1936 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1937 index = nextIndex;
1939 else
1940 index++;
1944 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1946 int i = 0;
1947 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)))))
1948 i++;
1949 if (index + i <= end-1)
1950 return index + i;
1951 else
1952 return -1;
1955 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)
1957 INT index, nextIndex;
1958 INT count,g_offset;
1959 INT prevCount = *pcGlyphs;
1961 count = syllable->base - syllable->start;
1963 g_offset = 0;
1964 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1965 while (index >= 0 && index < (glyph_index->base - glyph_index->start))
1967 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, "half");
1968 if (nextIndex > GSUB_E_NOGLYPH)
1970 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1971 g_offset += (*pcGlyphs - prevCount);
1972 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start, g_offset);
1975 index+=2;
1976 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1980 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)
1982 INT nextIndex;
1983 INT prevCount = *pcGlyphs;
1985 if (syllable->ralf >= 0)
1987 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1988 if (nextIndex > GSUB_E_NOGLYPH)
1990 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1991 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1996 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1998 int i = 0;
1999 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2000 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2001 is_consonant(lexical(pwChars[index+i+1])))))
2002 i++;
2003 if (index + i <= end-1)
2004 return index+i;
2005 else
2006 return -1;
2009 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)
2011 INT index, nextIndex;
2012 INT count, g_offset;
2013 INT prevCount = *pcGlyphs;
2015 count = syllable->end - syllable->base;
2017 g_offset = 0;
2018 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2020 while (index >= 0)
2022 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2023 if (nextIndex > GSUB_E_NOGLYPH)
2025 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2026 g_offset += (*pcGlyphs - prevCount);
2027 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start, g_offset);
2030 index+=2;
2031 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2035 static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllables, INT syllable_count, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical)
2037 int c;
2038 int overall_shift = 0;
2039 const GSUB_Feature *locl = load_GSUB_feature(hdc, psa, psc, "locl");
2040 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2041 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2042 const GSUB_Feature *rkrf = load_GSUB_feature(hdc, psa, psc, "rkrf");
2043 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2044 const GSUB_Feature *vatu = load_GSUB_feature(hdc, psa, psc, "vatu");
2045 const GSUB_Feature *cjct = load_GSUB_feature(hdc, psa, psc, "cjct");
2046 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2047 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2048 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2049 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2050 IndicSyllable glyph_indexs;
2052 for (c = 0; c < syllable_count; c++)
2054 int old_end;
2055 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2056 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2057 old_end = glyph_indexs.end;
2059 if (locl)
2061 TRACE("applying feature locl\n");
2062 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2064 if (nukt)
2066 TRACE("applying feature nukt\n");
2067 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2069 if (akhn)
2071 TRACE("applying feature akhn\n");
2072 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2074 if (rphf)
2075 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2076 if (rkrf)
2078 TRACE("applying feature rkrf\n");
2079 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2081 if (pref)
2082 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "pref");
2083 if (blwf)
2084 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2085 if (half)
2086 Apply_Indic_Half(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2087 if (pstf)
2089 TRACE("applying feature pstf\n");
2090 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2092 if (vatu)
2094 TRACE("applying feature vatu\n");
2095 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2097 if (cjct)
2099 TRACE("applying feature cjct\n");
2100 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2103 overall_shift += glyph_indexs.end - old_end;
2107 static int sinhala_lex(WCHAR c)
2109 switch (c)
2111 case 0x0DCA: return lex_Halant;
2112 case 0x0DCF:
2113 case 0x0DDF:
2114 case 0x0DD8: return lex_Matra_post;
2115 case 0x0DD9:
2116 case 0x0DDB: return lex_Matra_pre;
2117 case 0x0DDA:
2118 case 0x0DDC: return lex_Matra_post;
2119 case 0x200D: return lex_ZWJ;
2120 case 0x200C: return lex_ZWNJ;
2121 case 0x00A0: return lex_NBSP;
2122 default:
2123 if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
2124 else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
2125 else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
2126 else if (c>=0x0DD0 && c <=0x0DD1) return lex_Matra_post;
2127 else if (c>=0x0DD2 && c <=0x0DD3) return lex_Matra_above;
2128 else if (c>=0x0DD4 && c <=0x0DD6) return lex_Matra_below;
2129 else if (c>=0x0DDD && c <=0x0DDE) return lex_Matra_post;
2130 else if (c>=0x0DF2 && c <=0x0DF3) return lex_Matra_post;
2131 else return lex_Generic;
2135 static const VowelComponents Sinhala_vowels[] = {
2136 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2137 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2138 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2139 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2140 {0x0000, {0x0000,0x0000,0x0}}};
2142 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2144 int cCount = cChars;
2145 int i;
2146 WCHAR *input;
2147 IndicSyllable *syllables = NULL;
2148 int syllable_count = 0;
2150 if (*pcGlyphs != cChars)
2152 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2153 return;
2156 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2158 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2160 /* Step 1: Decompose multi part vowels */
2161 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels);
2163 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2165 /* Step 2: Reorder within Syllables */
2166 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala);
2167 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2169 /* Step 3: Strip dangling joiners */
2170 for (i = 0; i < cCount; i++)
2172 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2173 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2174 input[i] = 0x0020;
2177 /* Step 4: Base Form application to syllables */
2178 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2179 *pcGlyphs = cCount;
2180 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex);
2182 HeapFree(GetProcessHeap(),0,input);
2183 HeapFree(GetProcessHeap(),0,syllables);
2186 static int devanagari_lex(WCHAR c)
2188 switch (c)
2190 case 0x0951:
2191 case 0x0952:
2192 case 0x0903: return lex_Modifier;
2193 case 0x0930: return lex_Ra;
2194 case 0x093C: return lex_Nukta;
2195 case 0x0940:
2196 case 0x093E: return lex_Matra_post;
2197 case 0x093F: return lex_Matra_pre;
2198 case 0x094D: return lex_Halant;
2199 case 0x0972: return lex_Vowel;
2200 case 0x200C: return lex_ZWNJ;
2201 case 0x200D: return lex_ZWJ;
2202 default:
2203 if (c>=0x0901 && c<=0x0902) return lex_Matra_above;
2204 else if (c>=0x0904 && c<=0x0914) return lex_Vowel;
2205 else if (c>=0x0915 && c<=0x0939) return lex_Consonant;
2206 else if (c>=0x0941 && c<=0x0944) return lex_Matra_below;
2207 else if (c>=0x0945 && c<=0x0948) return lex_Matra_above;
2208 else if (c>=0x0949 && c<=0x094C) return lex_Matra_post;
2209 else if (c>=0x0953 && c<=0x0954) return lex_Modifier;
2210 else if (c>=0x0958 && c<=0x095F) return lex_Consonant;
2211 else if (c>=0x0960 && c<=0x0961) return lex_Vowel;
2212 else if (c>=0x0962 && c<=0x0963) return lex_Matra_below;
2213 else if (c>=0x097B && c<=0x097C) return lex_Consonant;
2214 else if (c>=0x097E && c<=0x097F) return lex_Consonant;
2215 else return lex_Generic;
2219 static const ConsonantComponents Devanagari_consonants[] ={
2220 {{0x0928, 0x093C, 0x00000}, 0x0929},
2221 {{0x0930, 0x093C, 0x00000}, 0x0931},
2222 {{0x0933, 0x093C, 0x00000}, 0x0934},
2223 {{0x0915, 0x093C, 0x00000}, 0x0958},
2224 {{0x0916, 0x093C, 0x00000}, 0x0959},
2225 {{0x0917, 0x093C, 0x00000}, 0x095A},
2226 {{0x091C, 0x093C, 0x00000}, 0x095B},
2227 {{0x0921, 0x093C, 0x00000}, 0x095C},
2228 {{0x0922, 0x093C, 0x00000}, 0x095D},
2229 {{0x092B, 0x093C, 0x00000}, 0x095E},
2230 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2232 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2234 int cCount = cChars;
2235 WCHAR *input;
2236 IndicSyllable *syllables = NULL;
2237 int syllable_count = 0;
2239 if (*pcGlyphs != cChars)
2241 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2242 return;
2245 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2246 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2248 /* Step 1: Compose Consonant and Nukta */
2249 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2250 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2252 /* Step 2: Reorder within Syllables */
2253 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari);
2254 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2255 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2256 *pcGlyphs = cCount;
2258 /* Step 3: Base Form application to syllables */
2259 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex);
2261 HeapFree(GetProcessHeap(),0,input);
2262 HeapFree(GetProcessHeap(),0,syllables);
2265 static int bengali_lex(WCHAR c)
2267 switch (c)
2269 case 0x0981: return lex_Modifier;
2270 case 0x09AC:
2271 case 0x09AF:
2272 case 0x09CE: return lex_Consonant;
2273 case 0x09B0: return lex_Ra;
2274 case 0x09BC: return lex_Nukta;
2275 case 0x09BF: return lex_Matra_pre;
2276 case 0x09D7:
2277 case 0x09BE:
2278 case 0x09C0: return lex_Matra_post;
2279 case 0x09CD: return lex_Halant;
2280 case 0x200C: return lex_ZWNJ;
2281 case 0x200D: return lex_ZWJ;
2282 default:
2283 if (c>=0x0982 && c<=0x0983) return lex_Matra_post;
2284 else if (c>=0x0985 && c<=0x0994) return lex_Vowel;
2285 else if (c>=0x0995 && c<=0x09B9) return lex_Consonant;
2286 else if (c>=0x09C1 && c<=0x09C4) return lex_Matra_below;
2287 else if (c>=0x09C7 && c<=0x09C8) return lex_Matra_pre;
2288 else if (c>=0x09DC && c<=0x09DF) return lex_Consonant;
2289 else if (c>=0x09E0 && c<=0x09E1) return lex_Vowel;
2290 else if (c>=0x09E2 && c<=0x09E3) return lex_Matra_below;
2291 else if (c>=0x09F0 && c<=0x09F1) return lex_Consonant;
2292 else return lex_Generic;
2296 static const VowelComponents Bengali_vowels[] = {
2297 {0x09CB, {0x09C7,0x09BE,0x0000}},
2298 {0x09CC, {0x09C7,0x09D7,0x0000}},
2299 {0x0000, {0x0000,0x0000,0x0000}}};
2301 static const ConsonantComponents Bengali_consonants[] = {
2302 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2303 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2304 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2305 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2306 {{0x0000,0x0000,0x0000}, 0x0000}};
2308 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2310 int cCount = cChars;
2311 WCHAR *input;
2312 IndicSyllable *syllables = NULL;
2313 int syllable_count = 0;
2315 if (*pcGlyphs != cChars)
2317 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2318 return;
2321 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2322 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2324 /* Step 1: Decompose Vowels and Compose Consonents */
2325 DecomposeVowels(hdc, input, &cCount, Bengali_vowels);
2326 ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2327 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2329 /* Step 2: Reorder within Syllables */
2330 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali);
2331 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2332 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2333 *pcGlyphs = cCount;
2335 /* Step 3: Initial form is only applied to the beginning of words */
2336 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2338 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2340 int index = cCount;
2341 int gCount = 1;
2342 if (index > 0) index++;
2344 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2348 /* Step 4: Base Form application to syllables */
2349 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex);
2351 HeapFree(GetProcessHeap(),0,input);
2352 HeapFree(GetProcessHeap(),0,syllables);
2355 static int gurmukhi_lex(WCHAR c)
2357 switch (c)
2359 case 0x0A30:
2360 case 0x0A35:
2361 case 0x0A39:
2362 case 0x0A2f: return lex_Consonant;
2363 case 0x0A3C: return lex_Nukta;
2364 case 0x0A3F: return lex_Matra_pre;
2365 case 0x0A03:
2366 case 0x0A3E:
2367 case 0x0A40: return lex_Matra_post;
2368 case 0x0A4D: return lex_Halant;
2369 case 0x0A70:
2370 case 0x0A71: return lex_Modifier;
2371 case 0x200C: return lex_ZWNJ;
2372 case 0x200D: return lex_ZWJ;
2373 default:
2374 if (c>=0x0A01 && c<=0x0A02) return lex_Modifier;
2375 else if (c>=0x0A05 && c<=0x0A14) return lex_Vowel;
2376 else if (c>=0x0A15 && c<=0x0A38) return lex_Consonant;
2377 else if (c>=0x0A41 && c<=0x0A42) return lex_Matra_below;
2378 else if (c>=0x0A47 && c<=0x0A4C) return lex_Matra_above;
2379 else if (c>=0x0A59 && c<=0x0A5E) return lex_Consonant;
2380 else return lex_Generic;
2384 static const ConsonantComponents Gurmukhi_consonants[] = {
2385 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2386 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2387 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2388 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2389 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2390 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2391 {{0x0000,0x0000,0x0000}, 0x0000}};
2393 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2395 int cCount = cChars;
2396 WCHAR *input;
2397 IndicSyllable *syllables = NULL;
2398 int syllable_count = 0;
2400 if (*pcGlyphs != cChars)
2402 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2403 return;
2406 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2407 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2409 /* Step 1: Compose Consonents */
2410 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2411 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2413 /* Step 2: Reorder within Syllables */
2414 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali);
2415 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2416 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2417 *pcGlyphs = cCount;
2419 /* Step 3: Base Form application to syllables */
2420 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex);
2422 HeapFree(GetProcessHeap(),0,input);
2423 HeapFree(GetProcessHeap(),0,syllables);
2426 static int gujarati_lex(WCHAR c)
2428 switch (c)
2430 case 0x0A83: return lex_Modifier;
2431 case 0x0AB0: return lex_Ra;
2432 case 0x0ABC: return lex_Nukta;
2433 case 0x0ABF: return lex_Matra_pre;
2434 case 0x0ABE:
2435 case 0x0AC0: return lex_Matra_post;
2436 case 0x0ACD: return lex_Halant;
2437 case 0x200C: return lex_ZWNJ;
2438 case 0x200D: return lex_ZWJ;
2439 default:
2440 if (c>=0x0A81 && c<=0x0A82) return lex_Modifier;
2441 else if (c>=0x0A85 && c<=0x0A94) return lex_Vowel;
2442 else if (c>=0x0A95 && c<=0x0AB9) return lex_Consonant;
2443 else if (c>=0x0AC1 && c<=0x0AC4) return lex_Matra_below;
2444 else if (c>=0x0AC5 && c<=0x0AC8) return lex_Matra_above;
2445 else if (c>=0x0AC9 && c<=0x0ACC) return lex_Matra_post;
2446 else if (c>=0x0AE0 && c<=0x0AE1) return lex_Vowel;
2447 else if (c>=0x0AE2 && c<=0x0AE3) return lex_Matra_below;
2448 else return lex_Generic;
2452 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2454 int cCount = cChars;
2455 WCHAR *input;
2456 IndicSyllable *syllables = NULL;
2457 int syllable_count = 0;
2459 if (*pcGlyphs != cChars)
2461 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2462 return;
2465 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2466 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2468 /* Step 1: Reorder within Syllables */
2469 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari);
2470 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2471 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2472 *pcGlyphs = cCount;
2474 /* Step 2: Base Form application to syllables */
2475 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex);
2477 HeapFree(GetProcessHeap(),0,input);
2478 HeapFree(GetProcessHeap(),0,syllables);
2481 static int oriya_lex(WCHAR c)
2483 switch (c)
2485 case 0x0B24:
2486 case 0x0B28:
2487 case 0x0B2F:
2488 case 0x0B5F:
2489 case 0x0B71:
2490 case 0x0B33: return lex_Consonant;
2491 case 0x0B30: return lex_Ra;
2492 case 0x0B3C: return lex_Nukta;
2493 case 0x0B3F:
2494 case 0x0B56: return lex_Matra_above;
2495 case 0x0B3E:
2496 case 0x0B57:
2497 case 0x0B40: return lex_Matra_post;
2498 case 0x0B47: return lex_Matra_pre;
2499 case 0x0B4D: return lex_Halant;
2500 case 0x200C: return lex_ZWNJ;
2501 case 0x200D: return lex_ZWJ;
2502 default:
2503 if (c>=0x0B01 && c<=0x0B03) return lex_Modifier;
2504 else if (c>=0x0B05 && c<=0x0B14) return lex_Vowel;
2505 else if (c>=0x0B15 && c<=0x0B39) return lex_Consonant;
2506 else if (c>=0x0B2C && c<=0x0B2E) return lex_Consonant;
2507 else if (c>=0x0B32 && c<=0x0B33) return lex_Consonant;
2508 else if (c>=0x0B41 && c<=0x0B44) return lex_Matra_below;
2509 else if (c>=0x0B48 && c<=0x0B4C) return lex_Composed_Vowel;
2510 else if (c>=0x0B5C && c<=0x0B5D) return lex_Consonant;
2511 else if (c>=0x0B60 && c<=0x0B61) return lex_Vowel;
2512 else if (c>=0x0B62 && c<=0x0B63) return lex_Matra_below;
2513 else return lex_Generic;
2517 static const VowelComponents Oriya_vowels[] = {
2518 {0x0B48, {0x0B47,0x0B56,0x0000}},
2519 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2520 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2521 {0x0000, {0x0000,0x0000,0x0000}}};
2523 static const ConsonantComponents Oriya_consonants[] = {
2524 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2525 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2526 {{0x0000,0x0000,0x0000}, 0x0000}};
2528 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2530 int cCount = cChars;
2531 WCHAR *input;
2532 IndicSyllable *syllables = NULL;
2533 int syllable_count = 0;
2535 if (*pcGlyphs != cChars)
2537 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2538 return;
2541 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2542 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2544 /* Step 1: Decompose Vowels and Compose Consonents */
2545 DecomposeVowels(hdc, input, &cCount, Oriya_vowels);
2546 ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2547 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2549 /* Step 2: Reorder within Syllables */
2550 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali);
2551 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2552 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2553 *pcGlyphs = cCount;
2555 /* Step 3: Base Form application to syllables */
2556 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex);
2558 HeapFree(GetProcessHeap(),0,input);
2559 HeapFree(GetProcessHeap(),0,syllables);
2562 static int tamil_lex(WCHAR c)
2564 switch (c)
2566 case 0x0BC0: return lex_Matra_above;
2567 case 0x0BCD: return lex_Halant;
2568 case 0x0BD7: return lex_Matra_post;
2569 case 0x200C: return lex_ZWNJ;
2570 case 0x200D: return lex_ZWJ;
2571 default:
2572 if (c>=0x0B95 && c<=0x0BB9) return lex_Consonant;
2573 else if (c>=0x0BBE && c<=0x0BBF) return lex_Matra_post;
2574 else if (c>=0x0BC1 && c<=0x0BC2) return lex_Matra_below;
2575 else if (c>=0x0BC6 && c<=0x0BC8) return lex_Matra_pre;
2576 else return lex_Generic;
2580 static const VowelComponents Tamil_vowels[] = {
2581 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2582 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2583 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2584 {0x0000, {0x0000,0x0000,0x0000}}};
2586 static const ConsonantComponents Tamil_consonants[] = {
2587 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2588 {{0x0000,0x0000,0x0000}, 0x0000}};
2590 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2592 int cCount = cChars;
2593 WCHAR *input;
2594 IndicSyllable *syllables = NULL;
2595 int syllable_count = 0;
2597 if (*pcGlyphs != cChars)
2599 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2600 return;
2603 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2604 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2606 /* Step 1: Decompose Vowels and Compose Consonents */
2607 DecomposeVowels(hdc, input, &cCount, Tamil_vowels);
2608 ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2609 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2611 /* Step 2: Reorder within Syllables */
2612 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Sinhala);
2613 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2614 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2615 *pcGlyphs = cCount;
2617 /* Step 3: Base Form application to syllables */
2618 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex);
2620 HeapFree(GetProcessHeap(),0,input);
2621 HeapFree(GetProcessHeap(),0,syllables);
2624 static int telugu_lex(WCHAR c)
2626 switch (c)
2628 case 0x0C4D: return lex_Halant;
2629 case 0x0C55: return lex_Matra_above;
2630 case 0x0C56: return lex_Matra_below;
2631 case 0x200C: return lex_ZWNJ;
2632 case 0x200D: return lex_ZWJ;
2633 default:
2634 if (c>=0x0C01 && c<=0x0C03) return lex_Matra_post;
2635 else if (c>=0x0C05 && c<=0x0C14) return lex_Vowel;
2636 else if (c>=0x0C15 && c<=0x0C39) return lex_Consonant;
2637 else if (c>=0x0C3E && c<=0x0C40) return lex_Matra_above;
2638 else if (c>=0x0C41 && c<=0x0C44) return lex_Matra_post;
2639 else if (c>=0x0C46 && c<=0x0C47) return lex_Matra_above;
2640 else if (c>=0x0C4A && c<=0x0C4C) return lex_Matra_above;
2641 else if (c>=0x0C58 && c<=0x0C59) return lex_Consonant;
2642 else if (c>=0x0C60 && c<=0x0C61) return lex_Vowel;
2643 else if (c>=0x0C62 && c<=0x0C63) return lex_Matra_below;
2644 else return lex_Generic;
2648 static const VowelComponents Telugu_vowels[] = {
2649 {0x0C48, {0x0C46,0x0C56,0x0000}},
2650 {0x0000, {0x0000,0x0000,0x0000}}};
2652 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2654 int cCount = cChars;
2655 WCHAR *input;
2656 IndicSyllable *syllables = NULL;
2657 int syllable_count = 0;
2659 if (*pcGlyphs != cChars)
2661 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2662 return;
2665 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2666 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2668 /* Step 1: Decompose Vowels */
2669 DecomposeVowels(hdc, input, &cCount, Telugu_vowels);
2670 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2672 /* Step 2: Reorder within Syllables */
2673 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali);
2674 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2675 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2676 *pcGlyphs = cCount;
2678 /* Step 3: Base Form application to syllables */
2679 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex);
2681 HeapFree(GetProcessHeap(),0,input);
2682 HeapFree(GetProcessHeap(),0,syllables);
2685 static int kannada_lex(WCHAR c)
2687 switch (c)
2689 case 0x0CB0: return lex_Ra;
2690 case 0x0CBC: return lex_Nukta;
2691 case 0x0CBE: return lex_Matra_post;
2692 case 0x0CBF: return lex_Matra_above;
2693 case 0x0CC6: return lex_Matra_above;
2694 case 0x0CCC: return lex_Matra_above;
2695 case 0x0CCD: return lex_Halant;
2696 case 0x0CCE: return lex_Consonant;
2697 case 0x200C: return lex_ZWNJ;
2698 case 0x200D: return lex_ZWJ;
2699 default:
2700 if (c>=0x0C82 && c<=0x0C83) return lex_Modifier;
2701 else if (c>=0x0C85 && c<=0x0C94) return lex_Vowel;
2702 else if (c>=0x0C95 && c<=0x0CB9) return lex_Consonant;
2703 else if (c>=0x0CC1 && c<=0x0CC4) return lex_Matra_post;
2704 else if (c>=0x0CD5 && c<=0x0CD6) return lex_Modifier;
2705 else if (c>=0x0CE0 && c<=0x0CE1) return lex_Vowel;
2706 else if (c>=0x0CE2 && c<=0x0CE3) return lex_Matra_below;
2707 else return lex_Generic;
2711 static const VowelComponents Kannada_vowels[] = {
2712 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2713 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2714 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2715 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2716 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2717 {0x0000, {0x0000,0x0000,0x0000}}};
2719 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2721 int cCount = cChars;
2722 WCHAR *input;
2723 IndicSyllable *syllables = NULL;
2724 int syllable_count = 0;
2726 if (*pcGlyphs != cChars)
2728 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2729 return;
2732 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2733 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2735 /* Step 1: Decompose Vowels */
2736 DecomposeVowels(hdc, input, &cCount, Kannada_vowels);
2737 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2739 /* Step 2: Reorder within Syllables */
2740 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada);
2741 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2742 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2743 *pcGlyphs = cCount;
2745 /* Step 3: Base Form application to syllables */
2746 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex);
2748 HeapFree(GetProcessHeap(),0,input);
2749 HeapFree(GetProcessHeap(),0,syllables);
2752 static int malayalam_lex(WCHAR c)
2754 switch (c)
2756 case 0x0D35: return lex_Consonant;
2757 case 0x0D4D: return lex_Halant;
2758 case 0x0D57: return lex_Matra_post;
2759 case 0x200C: return lex_ZWNJ;
2760 case 0x200D: return lex_ZWJ;
2761 default:
2762 if (c>=0x0D02 && c<=0x0D03) return lex_Modifier;
2763 else if (c>=0x0D05 && c<=0x0D14) return lex_Vowel;
2764 else if (c>=0x0D15 && c<=0x0D39) return lex_Consonant;
2765 else if (c>=0x0D3E && c<=0x0D44) return lex_Matra_post;
2766 else if (c>=0x0D46 && c<=0x0D48) return lex_Matra_pre;
2767 else if (c>=0x0D60 && c<=0x0D61) return lex_Vowel;
2768 else if (c>=0x0D62 && c<=0x0D63) return lex_Matra_below;
2769 else return lex_Generic;
2773 static const VowelComponents Malayalam_vowels[] = {
2774 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2775 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2776 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2777 {0x0000, {0x0000,0x0000,0x0000}}};
2779 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2781 int cCount = cChars;
2782 WCHAR *input;
2783 IndicSyllable *syllables = NULL;
2784 int syllable_count = 0;
2786 if (*pcGlyphs != cChars)
2788 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2789 return;
2792 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2793 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2795 /* Step 1: Decompose Vowels */
2796 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels);
2797 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2799 /* Step 2: Reorder within Syllables */
2800 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Malayalam);
2801 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2802 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2803 *pcGlyphs = cCount;
2805 /* Step 3: Base Form application to syllables */
2806 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex);
2808 HeapFree(GetProcessHeap(),0,input);
2809 HeapFree(GetProcessHeap(),0,syllables);
2812 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)
2814 int i,k;
2816 for (i = 0; i < cGlyphs; i++)
2818 int char_index[20];
2819 int char_count = 0;
2821 for (k = 0; k < cChars; k++)
2823 if (pwLogClust[k] == i)
2825 char_index[char_count] = k;
2826 char_count++;
2830 if (char_count == 0)
2832 FIXME("No chars in this glyph? Must be an error\n");
2833 continue;
2836 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2838 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2839 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2841 else
2842 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2845 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2846 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2849 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 )
2851 int i,k;
2852 int initGlyph, finaGlyph;
2853 INT dirR, dirL;
2854 BYTE *spaces;
2856 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2857 memset(spaces,0,cGlyphs);
2859 if (!psa->fLogicalOrder && psa->fRTL)
2861 initGlyph = cGlyphs-1;
2862 finaGlyph = 0;
2863 dirR = 1;
2864 dirL = -1;
2866 else
2868 initGlyph = 0;
2869 finaGlyph = cGlyphs-1;
2870 dirR = -1;
2871 dirL = 1;
2874 for (i = 0; i < cGlyphs; i++)
2876 for (k = 0; k < cChars; k++)
2877 if (pwLogClust[k] == i)
2879 if (pwcChars[k] == 0x0020)
2880 spaces[i] = 1;
2884 for (i = 0; i < cGlyphs; i++)
2886 int char_index[20];
2887 int char_count = 0;
2888 BOOL isInit, isFinal;
2890 for (k = 0; k < cChars; k++)
2892 if (pwLogClust[k] == i)
2894 char_index[char_count] = k;
2895 char_count++;
2899 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2900 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2902 if (char_count == 0)
2904 FIXME("No chars in this glyph? Must be an error\n");
2905 continue;
2908 if (char_count == 1)
2910 if (pwcChars[char_index[0]] == 0x0020) /* space */
2912 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2913 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2915 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2916 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2917 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2919 if (!isInit && !isFinal)
2920 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2921 else if (isInit)
2922 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2923 else
2924 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2926 else if (!isInit)
2928 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2929 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2930 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2931 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2932 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2933 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2934 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2935 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2936 else
2937 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2939 else if (!isInit && !isFinal)
2940 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2941 else
2942 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2944 else if (char_count == 2)
2946 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2947 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2948 else if (!isInit)
2949 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2950 else
2951 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2953 else if (!isInit && !isFinal)
2954 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2955 else
2956 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2959 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2960 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2961 HeapFree(GetProcessHeap(),0,spaces);
2964 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 )
2966 int i,k;
2967 int finaGlyph;
2968 INT dirL;
2969 BYTE *spaces;
2971 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2972 memset(spaces,0,cGlyphs);
2974 if (!psa->fLogicalOrder && psa->fRTL)
2976 finaGlyph = 0;
2977 dirL = -1;
2979 else
2981 finaGlyph = cGlyphs-1;
2982 dirL = 1;
2985 for (i = 0; i < cGlyphs; i++)
2987 for (k = 0; k < cChars; k++)
2988 if (pwLogClust[k] == i)
2990 if (pwcChars[k] == 0x0020)
2991 spaces[i] = 1;
2995 for (i = 0; i < cGlyphs; i++)
2997 int char_index[20];
2998 int char_count = 0;
3000 for (k = 0; k < cChars; k++)
3002 if (pwLogClust[k] == i)
3004 char_index[char_count] = k;
3005 char_count++;
3009 if (char_count == 0)
3011 FIXME("No chars in this glyph? Must be an error\n");
3012 continue;
3015 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3017 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3018 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3020 else if (i == finaGlyph)
3021 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3022 else
3023 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3026 HeapFree(GetProcessHeap(),0,spaces);
3027 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3028 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3030 /* Do not allow justification between marks and their base */
3031 for (i = 0; i < cGlyphs; i++)
3033 if (!pGlyphProp[i].sva.fClusterStart)
3034 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3038 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)
3040 int i,k;
3042 for (i = 0; i < cGlyphs; i++)
3044 int char_index[20];
3045 int char_count = 0;
3047 for (k = 0; k < cChars; k++)
3049 if (pwLogClust[k] == i)
3051 char_index[char_count] = k;
3052 char_count++;
3056 if (char_count == 0)
3058 FIXME("No chars in this glyph? Must be an error\n");
3059 continue;
3062 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3064 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3065 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3067 else
3068 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3070 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3071 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3074 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)
3076 int i,k;
3078 for (i = 0; i < cGlyphs; i++)
3080 int char_index[20];
3081 int char_count = 0;
3083 for (k = 0; k < cChars; k++)
3085 if (pwLogClust[k] == i)
3087 char_index[char_count] = k;
3088 char_count++;
3092 if (char_count == 0)
3094 FIXME("No chars in this glyph? Must be an error\n");
3095 continue;
3098 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3100 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3101 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3103 else
3104 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3106 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3107 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3109 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3110 for (i = 0; i < cGlyphs; i++)
3112 if (!pGlyphProp[i].sva.fClusterStart)
3114 pGlyphProp[i].sva.fDiacritic = 0;
3115 pGlyphProp[i].sva.fZeroWidth = 0;
3120 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)
3122 int i,k;
3124 for (i = 0; i < cGlyphs; i++)
3126 int char_index[20];
3127 int char_count = 0;
3129 for (k = 0; k < cChars; k++)
3131 if (pwLogClust[k] == i)
3133 char_index[char_count] = k;
3134 char_count++;
3138 if (char_count == 0)
3140 FIXME("No chars in this glyph? Must be an error\n");
3141 continue;
3144 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3146 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3147 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3149 else
3150 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3152 pGlyphProp[i].sva.fClusterStart = 0;
3153 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3154 switch (lexical(pwcChars[char_index[k]]))
3156 case lex_Matra_pre:
3157 case lex_Matra_post:
3158 case lex_Matra_above:
3159 case lex_Matra_below:
3160 case lex_Modifier:
3161 break;
3162 default:
3163 pGlyphProp[i].sva.fClusterStart = 1;
3164 break;
3167 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3170 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 )
3172 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3175 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 )
3177 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3180 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 )
3182 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3185 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 )
3187 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3190 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 )
3192 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3195 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 )
3197 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3200 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 )
3202 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3205 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 )
3207 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3210 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 )
3212 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3215 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)
3217 if (ShapingData[psa->eScript].charGlyphPropProc)
3218 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3219 else
3220 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3223 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3225 if (ShapingData[psa->eScript].contextProc)
3226 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3229 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)
3231 int i;
3232 INT dirL;
3234 if (!rpRangeProperties)
3235 return;
3237 if (!psc->GSUB_Table)
3238 psc->GSUB_Table = load_gsub_table(hdc);
3240 if (!psc->GSUB_Table)
3241 return;
3243 if (!psa->fLogicalOrder && psa->fRTL)
3244 dirL = -1;
3245 else
3246 dirL = 1;
3248 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3250 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3251 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3255 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3257 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3258 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3260 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3263 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3265 const GSUB_Feature *feature;
3266 int i;
3268 if (!ShapingData[psa->eScript].requiredFeatures)
3269 return S_OK;
3271 if (!psc->GSUB_Table)
3272 psc->GSUB_Table = load_gsub_table(hdc);
3274 /* we need to have at least one of the required features */
3275 i = 0;
3276 while (ShapingData[psa->eScript].requiredFeatures[i])
3278 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3279 if (feature)
3280 return S_OK;
3281 i++;
3284 return USP_E_SCRIPT_NOT_IN_FONT;