xcopy: Fix varargs handling for 64-bit.
[wine/multimedia.git] / dlls / usp10 / shape.c
blob0b1af464dc87fbe6181bcac7f5ba69a99e0bfc25
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 indic_syllabic_table[];
75 extern const unsigned short wine_shaping_table[];
76 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
78 enum joining_types {
79 jtU,
80 jtT,
81 jtR,
82 jtL,
83 jtD,
84 jtC
87 enum joined_forms {
88 Xn=0,
89 Xr,
90 Xl,
91 Xm,
92 /* Syriac Alaph */
93 Afj,
94 Afn,
95 Afx
98 #ifdef WORDS_BIGENDIAN
99 #define GET_BE_WORD(x) (x)
100 #else
101 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
102 #endif
104 /* These are all structures needed for the GSUB table */
105 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
106 #define GSUB_E_NOFEATURE -2
107 #define GSUB_E_NOGLYPH -1
109 typedef struct {
110 DWORD version;
111 WORD ScriptList;
112 WORD FeatureList;
113 WORD LookupList;
114 } GSUB_Header;
116 typedef struct {
117 CHAR ScriptTag[4];
118 WORD Script;
119 } GSUB_ScriptRecord;
121 typedef struct {
122 WORD ScriptCount;
123 GSUB_ScriptRecord ScriptRecord[1];
124 } GSUB_ScriptList;
126 typedef struct {
127 CHAR LangSysTag[4];
128 WORD LangSys;
129 } GSUB_LangSysRecord;
131 typedef struct {
132 WORD DefaultLangSys;
133 WORD LangSysCount;
134 GSUB_LangSysRecord LangSysRecord[1];
135 } GSUB_Script;
137 typedef struct {
138 WORD LookupOrder; /* Reserved */
139 WORD ReqFeatureIndex;
140 WORD FeatureCount;
141 WORD FeatureIndex[1];
142 } GSUB_LangSys;
144 typedef struct {
145 CHAR FeatureTag[4];
146 WORD Feature;
147 } GSUB_FeatureRecord;
149 typedef struct {
150 WORD FeatureCount;
151 GSUB_FeatureRecord FeatureRecord[1];
152 } GSUB_FeatureList;
154 typedef struct {
155 WORD FeatureParams; /* Reserved */
156 WORD LookupCount;
157 WORD LookupListIndex[1];
158 } GSUB_Feature;
160 typedef struct {
161 WORD LookupCount;
162 WORD Lookup[1];
163 } GSUB_LookupList;
165 typedef struct {
166 WORD LookupType;
167 WORD LookupFlag;
168 WORD SubTableCount;
169 WORD SubTable[1];
170 } GSUB_LookupTable;
172 typedef struct {
173 WORD CoverageFormat;
174 WORD GlyphCount;
175 WORD GlyphArray[1];
176 } GSUB_CoverageFormat1;
178 typedef struct {
179 WORD Start;
180 WORD End;
181 WORD StartCoverageIndex;
182 } GSUB_RangeRecord;
184 typedef struct {
185 WORD CoverageFormat;
186 WORD RangeCount;
187 GSUB_RangeRecord RangeRecord[1];
188 } GSUB_CoverageFormat2;
190 typedef struct {
191 WORD SubstFormat; /* = 1 */
192 WORD Coverage;
193 WORD DeltaGlyphID;
194 } GSUB_SingleSubstFormat1;
196 typedef struct {
197 WORD SubstFormat; /* = 2 */
198 WORD Coverage;
199 WORD GlyphCount;
200 WORD Substitute[1];
201 }GSUB_SingleSubstFormat2;
203 typedef struct {
204 WORD SubstFormat; /* = 1 */
205 WORD Coverage;
206 WORD SequenceCount;
207 WORD Sequence[1];
208 }GSUB_MultipleSubstFormat1;
210 typedef struct {
211 WORD GlyphCount;
212 WORD Substitute[1];
213 }GSUB_Sequence;
215 typedef struct {
216 WORD SubstFormat; /* = 1 */
217 WORD Coverage;
218 WORD LigSetCount;
219 WORD LigatureSet[1];
220 }GSUB_LigatureSubstFormat1;
222 typedef struct {
223 WORD LigatureCount;
224 WORD Ligature[1];
225 }GSUB_LigatureSet;
227 typedef struct{
228 WORD LigGlyph;
229 WORD CompCount;
230 WORD Component[1];
231 }GSUB_Ligature;
233 typedef struct{
234 WORD SequenceIndex;
235 WORD LookupListIndex;
237 }GSUB_SubstLookupRecord;
239 typedef struct{
240 WORD SubstFormat; /* = 1 */
241 WORD Coverage;
242 WORD ChainSubRuleSetCount;
243 WORD ChainSubRuleSet[1];
244 }GSUB_ChainContextSubstFormat1;
246 typedef struct {
247 WORD SubstFormat; /* = 3 */
248 WORD BacktrackGlyphCount;
249 WORD Coverage[1];
250 }GSUB_ChainContextSubstFormat3_1;
252 typedef struct{
253 WORD InputGlyphCount;
254 WORD Coverage[1];
255 }GSUB_ChainContextSubstFormat3_2;
257 typedef struct{
258 WORD LookaheadGlyphCount;
259 WORD Coverage[1];
260 }GSUB_ChainContextSubstFormat3_3;
262 typedef struct{
263 WORD SubstCount;
264 GSUB_SubstLookupRecord SubstLookupRecord[1];
265 }GSUB_ChainContextSubstFormat3_4;
267 typedef struct {
268 WORD SubstFormat; /* = 1 */
269 WORD Coverage;
270 WORD AlternateSetCount;
271 WORD AlternateSet[1];
272 } GSUB_AlternateSubstFormat1;
274 typedef struct{
275 WORD GlyphCount;
276 WORD Alternate[1];
277 } GSUB_AlternateSet;
279 /* These are all structures needed for the GDEF table */
280 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
282 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
284 typedef struct {
285 DWORD Version;
286 WORD GlyphClassDef;
287 WORD AttachList;
288 WORD LigCaretList;
289 WORD MarkAttachClassDef;
290 } GDEF_Header;
292 typedef struct {
293 WORD ClassFormat;
294 WORD StartGlyph;
295 WORD GlyphCount;
296 WORD ClassValueArray[1];
297 } GDEF_ClassDefFormat1;
299 typedef struct {
300 WORD Start;
301 WORD End;
302 WORD Class;
303 } GDEF_ClassRangeRecord;
305 typedef struct {
306 WORD ClassFormat;
307 WORD ClassRangeCount;
308 GDEF_ClassRangeRecord ClassRangeRecord[1];
309 } GDEF_ClassDefFormat2;
311 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
313 typedef struct tagVowelComponents
315 WCHAR base;
316 WCHAR parts[3];
317 } VowelComponents;
319 typedef struct tagConsonantComponents
321 WCHAR parts[3];
322 WCHAR output;
323 } ConsonantComponents;
325 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
327 /* the orders of joined_forms and contextual_features need to line up */
328 static const char* contextual_features[] =
330 "isol",
331 "fina",
332 "init",
333 "medi",
334 /* Syriac Alaph */
335 "med2",
336 "fin2",
337 "fin3"
340 static OPENTYPE_FEATURE_RECORD standard_features[] =
342 { MS_MAKE_TAG('l','i','g','a'), 1},
343 { MS_MAKE_TAG('c','l','i','g'), 1},
346 static OPENTYPE_FEATURE_RECORD arabic_features[] =
348 { MS_MAKE_TAG('r','l','i','g'), 1},
349 { MS_MAKE_TAG('c','a','l','t'), 1},
350 { MS_MAKE_TAG('l','i','g','a'), 1},
351 { MS_MAKE_TAG('d','l','i','g'), 1},
352 { MS_MAKE_TAG('c','s','w','h'), 1},
353 { MS_MAKE_TAG('m','s','e','t'), 1},
356 static const char* required_arabic_features[] =
358 "fina",
359 "init",
360 "medi",
361 "rlig",
362 NULL
365 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
367 { MS_MAKE_TAG('d','l','i','g'), 1},
370 static OPENTYPE_FEATURE_RECORD syriac_features[] =
372 { MS_MAKE_TAG('r','l','i','g'), 1},
373 { MS_MAKE_TAG('c','a','l','t'), 1},
374 { MS_MAKE_TAG('l','i','g','a'), 1},
375 { MS_MAKE_TAG('d','l','i','g'), 1},
378 static const char* required_syriac_features[] =
380 "fina",
381 "fin2",
382 "fin3",
383 "init",
384 "medi",
385 "med2",
386 "rlig",
387 NULL
390 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
392 /* Presentation forms */
393 { MS_MAKE_TAG('b','l','w','s'), 1},
394 { MS_MAKE_TAG('a','b','v','s'), 1},
395 { MS_MAKE_TAG('p','s','t','s'), 1},
398 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
400 { MS_MAKE_TAG('a','b','v','s'), 1},
401 { MS_MAKE_TAG('b','l','w','s'), 1},
404 static OPENTYPE_FEATURE_RECORD thai_features[] =
406 { MS_MAKE_TAG('c','c','m','p'), 1},
409 static const char* required_lao_features[] =
411 "ccmp",
412 NULL
415 static const char* required_devanagari_features[] =
417 "nukt",
418 "akhn",
419 "rphf",
420 "blwf",
421 "half",
422 "vatu",
423 "pres",
424 "abvs",
425 "blws",
426 "psts",
427 "haln",
428 NULL
431 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
433 { MS_MAKE_TAG('p','r','e','s'), 1},
434 { MS_MAKE_TAG('a','b','v','s'), 1},
435 { MS_MAKE_TAG('b','l','w','s'), 1},
436 { MS_MAKE_TAG('p','s','t','s'), 1},
437 { MS_MAKE_TAG('h','a','l','n'), 1},
438 { MS_MAKE_TAG('c','a','l','t'), 1},
441 static const char* required_bengali_features[] =
443 "nukt",
444 "akhn",
445 "rphf",
446 "blwf",
447 "half",
448 "vatu",
449 "pstf",
450 "init",
451 "abvs",
452 "blws",
453 "psts",
454 "haln",
455 NULL
458 static const char* required_gurmukhi_features[] =
460 "nukt",
461 "akhn",
462 "rphf",
463 "blwf",
464 "half",
465 "pstf",
466 "vatu",
467 "cjct",
468 "pres",
469 "abvs",
470 "blws",
471 "psts",
472 "haln",
473 "calt",
474 NULL
477 static const char* required_oriya_features[] =
479 "nukt",
480 "akhn",
481 "rphf",
482 "blwf",
483 "pstf",
484 "cjct",
485 "pres",
486 "abvs",
487 "blws",
488 "psts",
489 "haln",
490 "calt",
491 NULL
494 static const char* required_tamil_features[] =
496 "nukt",
497 "akhn",
498 "rphf",
499 "pref",
500 "half",
501 "pres",
502 "abvs",
503 "blws",
504 "psts",
505 "haln",
506 "calt",
507 NULL
510 static const char* required_telugu_features[] =
512 "nukt",
513 "akhn",
514 "rphf",
515 "pref",
516 "half",
517 "pstf",
518 "cjct",
519 "pres",
520 "abvs",
521 "blws",
522 "psts",
523 "haln",
524 "calt",
525 NULL
528 typedef struct ScriptShapeDataTag {
529 TEXTRANGE_PROPERTIES defaultTextRange;
530 const char** requiredFeatures;
531 CHAR otTag[5];
532 CHAR newOtTag[5];
533 ContextualShapingProc contextProc;
534 ShapeCharGlyphPropProc charGlyphPropProc;
535 } ScriptShapeData;
537 /* in order of scripts */
538 static const ScriptShapeData ShapingData[] =
540 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
541 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
542 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
543 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
544 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
545 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
546 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
547 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
548 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
549 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
550 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
551 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
552 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
553 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
554 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
555 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
556 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
557 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
558 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
559 {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
560 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
561 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
562 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
563 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
564 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
565 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
566 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
567 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
568 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
569 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
570 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
571 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
572 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
573 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
574 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
575 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
576 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
577 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
578 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
579 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
580 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
581 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
582 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
583 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
586 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
588 const GSUB_CoverageFormat1* cf1;
590 cf1 = table;
592 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
594 int count = GET_BE_WORD(cf1->GlyphCount);
595 int i;
596 TRACE("Coverage Format 1, %i glyphs\n",count);
597 for (i = 0; i < count; i++)
598 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
599 return i;
600 return -1;
602 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
604 const GSUB_CoverageFormat2* cf2;
605 int i;
606 int count;
607 cf2 = (const GSUB_CoverageFormat2*)cf1;
609 count = GET_BE_WORD(cf2->RangeCount);
610 TRACE("Coverage Format 2, %i ranges\n",count);
611 for (i = 0; i < count; i++)
613 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
614 return -1;
615 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
616 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
618 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
619 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
622 return -1;
624 else
625 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
627 return -1;
630 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
632 const GSUB_ScriptList *script;
633 const GSUB_Script *deflt = NULL;
634 int i;
635 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
637 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
638 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
640 const GSUB_Script *scr;
641 int offset;
643 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
644 scr = (const GSUB_Script*)((const BYTE*)script + offset);
646 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
647 return scr;
648 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
649 deflt = scr;
651 return deflt;
654 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
656 int i;
657 int offset;
658 const GSUB_LangSys *Lang;
660 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
662 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
664 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
665 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
667 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
668 return Lang;
670 offset = GET_BE_WORD(script->DefaultLangSys);
671 if (offset)
673 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
674 return Lang;
676 return NULL;
679 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
681 int i;
682 const GSUB_FeatureList *feature;
683 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
685 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
686 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
688 int index = GET_BE_WORD(lang->FeatureIndex[i]);
689 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
691 const GSUB_Feature *feat;
692 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
693 return feat;
696 return NULL;
699 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
701 int j;
702 TRACE("Single Substitution Subtable\n");
704 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
706 int offset;
707 const GSUB_SingleSubstFormat1 *ssf1;
708 offset = GET_BE_WORD(look->SubTable[j]);
709 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
710 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
712 int offset = GET_BE_WORD(ssf1->Coverage);
713 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
714 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
716 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
717 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
718 TRACE(" 0x%x\n",glyphs[glyph_index]);
719 return glyph_index + 1;
722 else
724 const GSUB_SingleSubstFormat2 *ssf2;
725 INT index;
726 INT offset;
728 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
729 offset = GET_BE_WORD(ssf1->Coverage);
730 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
731 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
732 TRACE(" Coverage index %i\n",index);
733 if (index != -1)
735 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
736 return GSUB_E_NOGLYPH;
738 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
739 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
740 TRACE("0x%x\n",glyphs[glyph_index]);
741 return glyph_index + 1;
745 return GSUB_E_NOGLYPH;
748 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
750 int j;
751 TRACE("Multiple Substitution Subtable\n");
753 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
755 int offset, index;
756 const GSUB_MultipleSubstFormat1 *msf1;
757 offset = GET_BE_WORD(look->SubTable[j]);
758 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
760 offset = GET_BE_WORD(msf1->Coverage);
761 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
762 if (index != -1)
764 const GSUB_Sequence *seq;
765 int sub_count;
766 int j;
767 offset = GET_BE_WORD(msf1->Sequence[index]);
768 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
769 sub_count = GET_BE_WORD(seq->GlyphCount);
770 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
772 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
773 glyphs[j] =glyphs[j-(sub_count-1)];
775 for (j = 0; j < sub_count; j++)
776 if (write_dir < 0)
777 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
778 else
779 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
781 *glyph_count = *glyph_count + (sub_count - 1);
783 if (TRACE_ON(uniscribe))
785 for (j = 0; j < sub_count; j++)
786 TRACE(" 0x%x",glyphs[glyph_index+j]);
787 TRACE("\n");
790 return glyph_index + sub_count;
793 return GSUB_E_NOGLYPH;
796 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
798 int j;
799 TRACE("Alternate Substitution Subtable\n");
801 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
803 int offset;
804 const GSUB_AlternateSubstFormat1 *asf1;
805 INT index;
807 offset = GET_BE_WORD(look->SubTable[j]);
808 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
809 offset = GET_BE_WORD(asf1->Coverage);
811 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
812 if (index != -1)
814 const GSUB_AlternateSet *as;
815 offset = GET_BE_WORD(asf1->AlternateSet[index]);
816 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
817 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
818 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
819 return GSUB_E_NOGLYPH;
821 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
822 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
823 TRACE(" 0x%x\n",glyphs[glyph_index]);
824 return glyph_index + 1;
827 return GSUB_E_NOGLYPH;
830 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
832 int j;
834 TRACE("Ligature Substitution Subtable\n");
835 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
837 const GSUB_LigatureSubstFormat1 *lsf1;
838 int offset,index;
840 offset = GET_BE_WORD(look->SubTable[j]);
841 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
842 offset = GET_BE_WORD(lsf1->Coverage);
843 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
844 TRACE(" Coverage index %i\n",index);
845 if (index != -1)
847 const GSUB_LigatureSet *ls;
848 int k, count;
850 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
851 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
852 count = GET_BE_WORD(ls->LigatureCount);
853 TRACE(" LigatureSet has %i members\n",count);
854 for (k = 0; k < count; k++)
856 const GSUB_Ligature *lig;
857 int CompCount,l,CompIndex;
859 offset = GET_BE_WORD(ls->Ligature[k]);
860 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
861 CompCount = GET_BE_WORD(lig->CompCount) - 1;
862 CompIndex = glyph_index+write_dir;
863 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
865 int CompGlyph;
866 CompGlyph = GET_BE_WORD(lig->Component[l]);
867 if (CompGlyph != glyphs[CompIndex])
868 break;
869 CompIndex += write_dir;
871 if (l == CompCount)
873 int replaceIdx = glyph_index;
874 if (write_dir < 0)
875 replaceIdx = glyph_index - CompCount;
877 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
878 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
879 TRACE("0x%x\n",glyphs[replaceIdx]);
880 if (CompCount > 0)
882 int j;
883 for (j = replaceIdx + 1; j < *glyph_count; j++)
884 glyphs[j] =glyphs[j+CompCount];
885 *glyph_count = *glyph_count - CompCount;
887 return replaceIdx + 1;
892 return GSUB_E_NOGLYPH;
895 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
897 int j;
898 BOOL done = FALSE;
900 TRACE("Chaining Contextual Substitution Subtable\n");
901 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
903 const GSUB_ChainContextSubstFormat1 *ccsf1;
904 int offset;
905 int dirLookahead = write_dir;
906 int dirBacktrack = -1 * write_dir;
908 offset = GET_BE_WORD(look->SubTable[j]);
909 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
910 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
912 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
913 continue;
915 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
917 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
918 continue;
920 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
922 int k;
923 int indexGlyphs;
924 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
925 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
926 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
927 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
928 int newIndex = glyph_index;
930 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
932 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
934 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
936 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
937 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
938 break;
940 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
941 continue;
942 TRACE("Matched Backtrack\n");
944 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
946 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
947 for (k = 0; k < indexGlyphs; k++)
949 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
950 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
951 break;
953 if (k != indexGlyphs)
954 continue;
955 TRACE("Matched IndexGlyphs\n");
957 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
959 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
961 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
962 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
963 break;
965 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
966 continue;
967 TRACE("Matched LookAhead\n");
969 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
971 if (GET_BE_WORD(ccsf3_4->SubstCount))
973 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
975 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
976 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
978 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
979 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
980 if (newIndex == -1)
982 ERR("Chain failed to generate a glyph\n");
983 continue;
986 return newIndex;
988 else return GSUB_E_NOGLYPH;
991 return -1;
994 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
996 int offset;
997 const GSUB_LookupTable *look;
999 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1000 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1001 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1002 switch(GET_BE_WORD(look->LookupType))
1004 case 1:
1005 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1006 case 2:
1007 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1008 case 3:
1009 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1010 case 4:
1011 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1012 case 6:
1013 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1014 default:
1015 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1017 return GSUB_E_NOGLYPH;
1020 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1022 int i;
1023 int out_index = GSUB_E_NOGLYPH;
1024 const GSUB_LookupList *lookup;
1026 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1028 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1029 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1031 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1032 if (out_index != GSUB_E_NOGLYPH)
1033 break;
1035 if (out_index == GSUB_E_NOGLYPH)
1036 TRACE("lookups found no glyphs\n");
1037 else
1039 int out2;
1040 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1041 if (out2!=GSUB_E_NOGLYPH)
1042 out_index = out2;
1044 return out_index;
1047 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1049 UINT charset;
1051 if (psc->userScript != 0)
1053 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1054 return ShapingData[psa->eScript].newOtTag;
1055 else
1056 return (char*)&psc->userScript;
1059 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1060 return ShapingData[psa->eScript].newOtTag;
1062 if (ShapingData[psa->eScript].otTag[0] != 0)
1063 return ShapingData[psa->eScript].otTag;
1066 * fall back to the font charset
1068 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1069 switch (charset)
1071 case ANSI_CHARSET: return "latn";
1072 case BALTIC_CHARSET: return "latn"; /* ?? */
1073 case CHINESEBIG5_CHARSET: return "hani";
1074 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1075 case GB2312_CHARSET: return "hani";
1076 case GREEK_CHARSET: return "grek";
1077 case HANGUL_CHARSET: return "hang";
1078 case RUSSIAN_CHARSET: return "cyrl";
1079 case SHIFTJIS_CHARSET: return "kana";
1080 case TURKISH_CHARSET: return "latn"; /* ?? */
1081 case VIETNAMESE_CHARSET: return "latn";
1082 case JOHAB_CHARSET: return "latn"; /* ?? */
1083 case ARABIC_CHARSET: return "arab";
1084 case HEBREW_CHARSET: return "hebr";
1085 case THAI_CHARSET: return "thai";
1086 default: return "latn";
1090 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1092 const GSUB_Feature *feature;
1093 int i;
1095 for (i = 0; i < psc->feature_count; i++)
1096 if (strncmp(psc->features[i].tag,feat,4)==0)
1097 return psc->features[i].feature;
1099 feature = NULL;
1101 if (psc->GSUB_Table)
1103 const GSUB_Script *script;
1104 const GSUB_LangSys *language;
1105 int attempt = 2;
1109 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1110 attempt--;
1111 if (script)
1113 if (psc->userLang != 0)
1114 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1115 else
1116 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1117 if (language)
1118 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1120 } while(attempt && !feature);
1122 /* try in the default (latin) table */
1123 if (!feature)
1125 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1126 if (script)
1128 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1129 if (language)
1130 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1135 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1137 psc->feature_count++;
1139 if (psc->features)
1140 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1141 else
1142 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1144 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1145 psc->features[psc->feature_count - 1].feature = feature;
1146 return feature;
1149 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)
1151 const GSUB_Feature *feature;
1153 feature = load_GSUB_feature(hdc, psa, psc, feat);
1154 if (!feature)
1155 return GSUB_E_NOFEATURE;
1157 TRACE("applying feature %s\n",feat);
1158 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1161 static VOID *load_gsub_table(HDC hdc)
1163 VOID* GSUB_Table = NULL;
1164 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1165 if (length != GDI_ERROR)
1167 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1168 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1169 TRACE("Loaded GSUB table of %i bytes\n",length);
1171 return GSUB_Table;
1174 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)
1176 WORD *glyphs;
1177 INT glyph_count = count;
1178 INT rc;
1180 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1181 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1182 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1183 if (rc > GSUB_E_NOGLYPH)
1184 rc = count - glyph_count;
1185 else
1186 rc = 0;
1188 HeapFree(GetProcessHeap(),0,glyphs);
1189 return rc;
1192 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1194 int offset;
1195 WORD class = 0;
1196 const GDEF_ClassDefFormat1 *cf1;
1198 if (!header)
1199 return 0;
1201 offset = GET_BE_WORD(header->GlyphClassDef);
1202 if (!offset)
1203 return 0;
1205 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1206 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1208 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1210 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1211 if (index < GET_BE_WORD(cf1->GlyphCount))
1212 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1215 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1217 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1218 int i, top;
1219 top = GET_BE_WORD(cf2->ClassRangeCount);
1220 for (i = 0; i < top; i++)
1222 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1223 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1225 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1226 break;
1230 else
1231 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1233 return class;
1236 static VOID *load_gdef_table(HDC hdc)
1238 VOID* GDEF_Table = NULL;
1239 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1240 if (length != GDI_ERROR)
1242 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1243 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1244 TRACE("Loaded GDEF table of %i bytes\n",length);
1246 return GDEF_Table;
1249 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1251 int i;
1253 if (!psc->GDEF_Table)
1254 psc->GDEF_Table = load_gdef_table(hdc);
1256 for (i = 0; i < cGlyphs; i++)
1258 WORD class;
1260 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1262 switch (class)
1264 case 0:
1265 case BaseGlyph:
1266 pGlyphProp[i].sva.fClusterStart = 1;
1267 pGlyphProp[i].sva.fDiacritic = 0;
1268 pGlyphProp[i].sva.fZeroWidth = 0;
1269 break;
1270 case LigatureGlyph:
1271 pGlyphProp[i].sva.fClusterStart = 1;
1272 pGlyphProp[i].sva.fDiacritic = 0;
1273 pGlyphProp[i].sva.fZeroWidth = 0;
1274 break;
1275 case MarkGlyph:
1276 pGlyphProp[i].sva.fClusterStart = 0;
1277 pGlyphProp[i].sva.fDiacritic = 1;
1278 pGlyphProp[i].sva.fZeroWidth = 1;
1279 break;
1280 case ComponentGlyph:
1281 pGlyphProp[i].sva.fClusterStart = 0;
1282 pGlyphProp[i].sva.fDiacritic = 0;
1283 pGlyphProp[i].sva.fZeroWidth = 0;
1284 break;
1285 default:
1286 ERR("Unknown glyph class %i\n",class);
1287 pGlyphProp[i].sva.fClusterStart = 1;
1288 pGlyphProp[i].sva.fDiacritic = 0;
1289 pGlyphProp[i].sva.fZeroWidth = 0;
1294 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1296 int i;
1298 for (i = 0; i < cGlyphs; i++)
1300 if (!pGlyphProp[i].sva.fClusterStart)
1302 int j;
1303 for (j = 0; j < cChars; j++)
1305 if (pwLogClust[j] == i)
1307 int k = j;
1308 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1309 k-=1;
1310 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1311 pwLogClust[j] = pwLogClust[k];
1318 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1320 if (changeCount == 0)
1321 return;
1322 else
1324 int i;
1325 int target_glyph = nextIndex - 1;
1326 int seeking_glyph;
1327 int target_index = -1;
1328 int replacing_glyph = -1;
1329 int changed = 0;
1332 if (changeCount > 0)
1333 target_glyph = nextIndex - (changeCount+1);
1335 seeking_glyph = target_glyph;
1337 do {
1338 if (write_dir > 0)
1339 for (i = 0; i < chars; i++)
1341 if (pwLogClust[i] == seeking_glyph)
1343 target_index = i;
1344 break;
1347 else
1348 for (i = chars - 1; i >= 0; i--)
1350 if (pwLogClust[i] == seeking_glyph)
1352 target_index = i;
1353 break;
1356 if (target_index == -1)
1357 seeking_glyph ++;
1359 while (target_index == -1 && seeking_glyph < chars);
1361 if (target_index == -1)
1363 ERR("Unable to find target glyph\n");
1364 return;
1367 if (changeCount < 0)
1369 /* merge glyphs */
1370 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1372 if (pwLogClust[i] == target_glyph)
1373 continue;
1374 if(pwLogClust[i] == replacing_glyph)
1375 pwLogClust[i] = target_glyph;
1376 else
1378 changed--;
1379 if (changed >= changeCount)
1381 replacing_glyph = pwLogClust[i];
1382 pwLogClust[i] = target_glyph;
1384 else
1385 break;
1389 /* renumber trailing indexes*/
1390 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1392 if (pwLogClust[i] != target_glyph)
1393 pwLogClust[i] += changeCount;
1396 else
1398 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1399 pwLogClust[i] += changeCount;
1404 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 )
1406 int i;
1408 if (psc->GSUB_Table)
1410 const GSUB_Feature *feature;
1412 feature = load_GSUB_feature(hdc, psa, psc, feat);
1413 if (!feature)
1414 return GSUB_E_NOFEATURE;
1416 i = 0;
1417 TRACE("applying feature %s\n",debugstr_an(feat,4));
1418 while(i < *pcGlyphs)
1420 INT nextIndex;
1421 INT prevCount = *pcGlyphs;
1422 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1423 if (nextIndex > GSUB_E_NOGLYPH)
1425 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1426 i = nextIndex;
1428 else
1429 i++;
1431 return *pcGlyphs;
1433 return GSUB_E_NOFEATURE;
1436 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1438 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1441 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1443 if (i + delta < 0)
1444 return 0;
1445 if ( i+ delta >= cchLen)
1446 return 0;
1448 i += delta;
1450 return chars[i];
1453 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1455 if (i + delta < 0)
1457 if (psa->fLinkBefore)
1458 return jtR;
1459 else
1460 return jtU;
1462 if ( i+ delta >= cchLen)
1464 if (psa->fLinkAfter)
1465 return jtL;
1466 else
1467 return jtU;
1470 i += delta;
1472 if (context_type[i] == jtT)
1473 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1474 else
1475 return context_type[i];
1478 static inline BOOL right_join_causing(CHAR joining_type)
1480 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1483 static inline BOOL left_join_causing(CHAR joining_type)
1485 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1488 static inline BOOL word_break_causing(WCHAR chr)
1490 /* we are working within a string of characters already guareented to
1491 be within one script, Syriac, so we do not worry about any character
1492 other than the space character outside of that range */
1493 return (chr == 0 || chr == 0x20 );
1497 * ContextualShape_Arabic
1499 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1501 CHAR *context_type;
1502 INT *context_shape;
1503 INT dirR, dirL;
1504 int i;
1506 if (*pcGlyphs != cChars)
1508 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1509 return;
1512 if (!psa->fLogicalOrder && psa->fRTL)
1514 dirR = 1;
1515 dirL = -1;
1517 else
1519 dirR = -1;
1520 dirL = 1;
1523 if (!psc->GSUB_Table)
1524 psc->GSUB_Table = load_gsub_table(hdc);
1526 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1527 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1529 for (i = 0; i < cChars; i++)
1530 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1532 for (i = 0; i < cChars; i++)
1534 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1535 context_shape[i] = Xr;
1536 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1537 context_shape[i] = Xl;
1538 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)))
1539 context_shape[i] = Xm;
1540 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1541 context_shape[i] = Xr;
1542 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1543 context_shape[i] = Xl;
1544 else
1545 context_shape[i] = Xn;
1548 /* Contextual Shaping */
1549 i = 0;
1550 while(i < *pcGlyphs)
1552 BOOL shaped = FALSE;
1554 if (psc->GSUB_Table)
1556 INT nextIndex;
1557 INT prevCount = *pcGlyphs;
1558 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1559 if (nextIndex > GSUB_E_NOGLYPH)
1561 i = nextIndex;
1562 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1564 shaped = (nextIndex > GSUB_E_NOGLYPH);
1567 if (!shaped)
1569 WORD newGlyph = pwOutGlyphs[i];
1570 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1572 /* fall back to presentation form B */
1573 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1574 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1575 pwOutGlyphs[i] = newGlyph;
1577 i++;
1581 HeapFree(GetProcessHeap(),0,context_shape);
1582 HeapFree(GetProcessHeap(),0,context_type);
1586 * ContextualShape_Syriac
1589 #define ALAPH 0x710
1590 #define DALATH 0x715
1591 #define RISH 0x72A
1593 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1595 CHAR *context_type;
1596 INT *context_shape;
1597 INT dirR, dirL;
1598 int i;
1600 if (*pcGlyphs != cChars)
1602 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1603 return;
1606 if (!psa->fLogicalOrder && psa->fRTL)
1608 dirR = 1;
1609 dirL = -1;
1611 else
1613 dirR = -1;
1614 dirL = 1;
1617 if (!psc->GSUB_Table)
1618 psc->GSUB_Table = load_gsub_table(hdc);
1620 if (!psc->GSUB_Table)
1621 return;
1623 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1624 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1626 for (i = 0; i < cChars; i++)
1627 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1629 for (i = 0; i < cChars; i++)
1631 if (pwcChars[i] == ALAPH)
1633 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1635 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1636 context_shape[i] = Afj;
1637 else if ( rchar != DALATH && rchar != RISH &&
1638 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1639 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1640 context_shape[i] = Afn;
1641 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1642 context_shape[i] = Afx;
1643 else
1644 context_shape[i] = Xn;
1646 else if (context_type[i] == jtR &&
1647 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1648 context_shape[i] = Xr;
1649 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1650 context_shape[i] = Xl;
1651 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)))
1652 context_shape[i] = Xm;
1653 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1654 context_shape[i] = Xr;
1655 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1656 context_shape[i] = Xl;
1657 else
1658 context_shape[i] = Xn;
1661 /* Contextual Shaping */
1662 i = 0;
1663 while(i < *pcGlyphs)
1665 INT nextIndex;
1666 INT prevCount = *pcGlyphs;
1667 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1668 if (nextIndex > GSUB_E_NOGLYPH)
1670 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1671 i = nextIndex;
1673 else
1674 i++;
1677 HeapFree(GetProcessHeap(),0,context_shape);
1678 HeapFree(GetProcessHeap(),0,context_type);
1682 * ContextualShape_Phags_pa
1685 #define phags_pa_CANDRABINDU 0xA873
1686 #define phags_pa_START 0xA840
1687 #define phags_pa_END 0xA87F
1689 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1691 INT *context_shape;
1692 INT dirR, dirL;
1693 int i;
1695 if (*pcGlyphs != cChars)
1697 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1698 return;
1701 if (!psa->fLogicalOrder && psa->fRTL)
1703 dirR = 1;
1704 dirL = -1;
1706 else
1708 dirR = -1;
1709 dirL = 1;
1712 if (!psc->GSUB_Table)
1713 psc->GSUB_Table = load_gsub_table(hdc);
1715 if (!psc->GSUB_Table)
1716 return;
1718 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1720 for (i = 0; i < cChars; i++)
1722 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1724 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1725 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1726 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1727 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1729 if (jrchar && jlchar)
1730 context_shape[i] = Xm;
1731 else if (jrchar)
1732 context_shape[i] = Xr;
1733 else if (jlchar)
1734 context_shape[i] = Xl;
1735 else
1736 context_shape[i] = Xn;
1738 else
1739 context_shape[i] = -1;
1742 /* Contextual Shaping */
1743 i = 0;
1744 while(i < *pcGlyphs)
1746 if (context_shape[i] >= 0)
1748 INT nextIndex;
1749 INT prevCount = *pcGlyphs;
1750 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1751 if (nextIndex > GSUB_E_NOGLYPH)
1753 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1754 i = nextIndex;
1756 else
1757 i++;
1759 else
1760 i++;
1763 HeapFree(GetProcessHeap(),0,context_shape);
1766 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1768 int i;
1770 /* Replace */
1771 pwOutChars[cWalk] = replacements[0];
1772 cWalk=cWalk+1;
1774 /* Insert */
1775 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1777 int j;
1778 for (j = *pcChars; j > cWalk; j--)
1779 pwOutChars[j] = pwOutChars[j-1];
1780 *pcChars= *pcChars+1;
1781 pwOutChars[cWalk] = replacements[i];
1782 cWalk = cWalk+1;
1786 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust)
1788 int i;
1789 int cWalk;
1790 int offset = 0;
1792 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1794 for (i = 0; vowels[i].base != 0x0; i++)
1796 if (pwOutChars[cWalk] == vowels[i].base)
1798 int j;
1799 int o = 1;
1800 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1801 if (vowels[i].parts[1]) { cWalk++; o++; }
1802 if (vowels[i].parts[2]) { cWalk++; o++; }
1803 offset += o;
1804 for (j = (cWalk - offset) + 1; j < *pcChars - offset; j ++)
1805 pwLogClust[j]+=o;
1806 break;
1812 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1814 int i;
1815 int offset = 0;
1816 int cWalk;
1818 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1820 for (i = 0; consonants[i].output!= 0x0; i++)
1822 int j;
1823 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1824 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1825 break;
1827 if (consonants[i].parts[j]==0x0) /* matched all */
1829 int k;
1830 j--;
1831 pwOutChars[cWalk] = consonants[i].output;
1832 for(k = cWalk+1; k < *pcChars - j; k++)
1833 pwOutChars[k] = pwOutChars[k+j];
1834 *pcChars = *pcChars - j;
1835 for (k = j ; k > 0; k--)
1836 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1837 offset += j;
1838 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1839 pwLogClust[k]--;
1840 break;
1843 cWalk++;
1847 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1849 if (s->ralf >= 0)
1851 int j;
1852 WORD Ra = pwChar[s->start];
1853 WORD H = pwChar[s->start+1];
1855 TRACE("Doing reorder of Ra to %i\n",s->base);
1856 for (j = s->start; j < s->base-1; j++)
1857 pwChar[j] = pwChar[j+2];
1858 pwChar[s->base-1] = Ra;
1859 pwChar[s->base] = H;
1861 s->ralf = s->base-1;
1862 s->base -= 2;
1866 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1868 if (s->ralf >= 0)
1870 int j,loc;
1871 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1872 WORD Ra = pwChar[s->start];
1873 WORD H = pwChar[s->start+1];
1874 for (loc = s->end; loc > stop; loc--)
1875 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1876 break;
1878 TRACE("Doing reorder of Ra to %i\n",loc);
1879 for (j = s->start; j < loc-1; j++)
1880 pwChar[j] = pwChar[j+2];
1881 pwChar[loc-1] = Ra;
1882 pwChar[loc] = H;
1884 s->ralf = loc-1;
1885 s->base -= 2;
1886 if (s->blwf >= 0) s->blwf -= 2;
1887 if (s->pref >= 0) s->pref -= 2;
1891 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1893 if (s->ralf >= 0)
1895 int j;
1896 WORD Ra = pwChar[s->start];
1897 WORD H = pwChar[s->start+1];
1899 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1900 for (j = s->start; j < s->end-1; j++)
1901 pwChar[j] = pwChar[j+2];
1902 pwChar[s->end-1] = Ra;
1903 pwChar[s->end] = H;
1905 s->ralf = s->end-1;
1906 s->base -= 2;
1907 if (s->blwf >= 0) s->blwf -= 2;
1908 if (s->pref >= 0) s->pref -= 2;
1912 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1914 int i;
1916 /* reorder Matras */
1917 if (s->end > s->base)
1919 for (i = 1; i <= s->end-s->base; i++)
1921 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1923 int j;
1924 WCHAR c = pwChar[s->base+i];
1925 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1926 for (j = s->base+i; j > s->base; j--)
1927 pwChar[j] = pwChar[j-1];
1928 pwChar[s->base] = c;
1930 if (s->ralf >= s->base) s->ralf++;
1931 if (s->blwf >= s->base) s->blwf++;
1932 if (s->pref >= s->base) s->pref++;
1933 s->base ++;
1939 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1941 int i;
1943 /* reorder Matras */
1944 if (s->end > s->base)
1946 for (i = 1; i <= s->end-s->base; i++)
1948 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1950 int j;
1951 WCHAR c = pwChar[s->base+i];
1952 TRACE("Doing reorder of %x to %i\n",c,s->start);
1953 for (j = s->base+i; j > s->start; j--)
1954 pwChar[j] = pwChar[j-1];
1955 pwChar[s->start] = c;
1957 if (s->ralf >= 0) s->ralf++;
1958 if (s->blwf >= 0) s->blwf++;
1959 if (s->pref >= 0) s->pref++;
1960 s->base ++;
1966 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1968 if (s->blwf >= 0 && g->blwf > g->base)
1970 int j,loc;
1971 int g_offset;
1972 for (loc = s->end; loc > s->blwf; loc--)
1973 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1974 break;
1976 g_offset = (loc - s->blwf) - 1;
1978 if (loc != s->blwf)
1980 WORD blwf = glyphs[g->blwf];
1981 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1982 /* do not care about the pwChar array anymore, just the glyphs */
1983 for (j = 0; j < g_offset; j++)
1984 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1985 glyphs[g->blwf + g_offset] = blwf;
1990 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1992 int i;
1994 /* reorder previously moved Matras to correct position*/
1995 for (i = s->start; i < s->base; i++)
1997 if (lexical(pwChar[i]) == lex_Matra_pre)
1999 int j;
2000 int g_start = g->start + i - s->start;
2001 if (g_start < g->base -1 )
2003 WCHAR og = glyphs[g_start];
2004 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2005 for (j = g_start; j < g->base-1; j++)
2006 glyphs[j] = glyphs[j+1];
2007 glyphs[g->base-1] = og;
2013 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2015 if (s->pref >= 0 && g->pref > g->base)
2017 int j;
2018 WCHAR og = glyphs[g->pref];
2019 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2020 for (j = g->pref; j > g->base; j--)
2021 glyphs[j] = glyphs[j-1];
2022 glyphs[g->base] = og;
2026 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2028 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2029 if (s->start == s->base && s->base == s->end) return;
2030 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2032 Reorder_Ra_follows_base(pwChar, s, lexical);
2033 Reorder_Matra_precede_base(pwChar, s, lexical);
2036 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2038 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2039 if (s->start == s->base && s->base == s->end) return;
2040 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2042 Reorder_Ra_follows_matra(pwChar, s, lexical);
2043 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2046 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2048 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2049 if (s->start == s->base && s->base == s->end) return;
2050 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2052 Reorder_Ra_follows_base(pwChar, s, lexical);
2053 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2056 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2058 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2059 if (s->start == s->base && s->base == s->end) return;
2060 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2062 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2063 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2066 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2068 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2069 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2070 if (s->start == s->base && s->base == s->end) return;
2071 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2073 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2076 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2078 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2079 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2080 if (s->start == s->base && s->base == s->end) return;
2081 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2083 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2084 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2088 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2090 if (shift == 0)
2091 return;
2093 if (glyph_index->start > index)
2094 glyph_index->start += shift;
2095 if (glyph_index->base > index)
2096 glyph_index->base+= shift;
2097 if (glyph_index->end > index)
2098 glyph_index->end+= shift;
2099 if (glyph_index->ralf > index)
2100 glyph_index->ralf+= shift;
2101 if (glyph_index->blwf > index)
2102 glyph_index->blwf+= shift;
2103 if (glyph_index->pref > index)
2104 glyph_index->pref+= shift;
2107 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 )
2109 int index = glyph_index->start;
2111 if (!feature)
2112 return;
2114 while(index <= glyph_index->end)
2116 INT nextIndex;
2117 INT prevCount = *pcGlyphs;
2118 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2119 if (nextIndex > GSUB_E_NOGLYPH)
2121 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2122 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2123 index = nextIndex;
2125 else
2126 index++;
2130 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2132 int i = 0;
2133 while (i + index < end - 1 && !(is_consonant(lexical(pwChars[index+i])) && (lexical(pwChars[index+i+1]) == lex_Halant || (index + i < end - 2 && lexical(pwChars[index+i+1]) == lex_Nukta && lexical(pwChars[index+i+2] == lex_Halant)))))
2134 i++;
2135 if (index + i <= end-1)
2136 return index + i;
2137 else
2138 return -1;
2141 static void Apply_Indic_PreBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const char* feature)
2143 INT index, nextIndex;
2144 INT count,g_offset;
2146 count = syllable->base - syllable->start;
2148 g_offset = 0;
2149 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2150 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2152 INT prevCount = *pcGlyphs;
2153 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2154 if (nextIndex > GSUB_E_NOGLYPH)
2156 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2157 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2158 g_offset += (*pcGlyphs - prevCount);
2161 index+=2;
2162 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2166 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)
2168 INT nextIndex;
2169 INT prevCount = *pcGlyphs;
2171 if (syllable->ralf >= 0)
2173 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2174 if (nextIndex > GSUB_E_NOGLYPH)
2176 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2177 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2182 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2184 int i = 0;
2185 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2186 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2187 is_consonant(lexical(pwChars[index+i+1])))))
2188 i++;
2189 if (index + i <= end-1)
2190 return index+i;
2191 else
2192 return -1;
2195 static void Apply_Indic_PostBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, BOOL modern, const char* feat)
2197 INT index, nextIndex;
2198 INT count, g_offset=0;
2199 INT ralf = syllable->ralf;
2201 count = syllable->end - syllable->base;
2203 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2205 while (index >= 0)
2207 INT prevCount = *pcGlyphs;
2208 if (ralf >=0 && ralf < index)
2210 g_offset--;
2211 ralf = -1;
2214 if (!modern)
2216 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2217 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2218 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2221 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2222 if (nextIndex > GSUB_E_NOGLYPH)
2224 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2225 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2226 g_offset += (*pcGlyphs - prevCount);
2228 else if (!modern)
2230 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2231 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2232 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2235 index+=2;
2236 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2240 static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllables, INT syllable_count, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, second_reorder_function second_reorder, BOOL modern)
2242 int c;
2243 int overall_shift = 0;
2244 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2245 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2246 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2247 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2248 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2249 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2250 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2251 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2252 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2253 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2254 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2255 IndicSyllable glyph_indexs;
2257 for (c = 0; c < syllable_count; c++)
2259 int old_end;
2260 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2261 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2262 old_end = glyph_indexs.end;
2264 if (locl)
2266 TRACE("applying feature locl\n");
2267 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2269 if (nukt)
2271 TRACE("applying feature nukt\n");
2272 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2274 if (akhn)
2276 TRACE("applying feature akhn\n");
2277 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2280 if (rphf)
2281 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2282 if (rkrf)
2284 TRACE("applying feature rkrf\n");
2285 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2287 if (pref)
2288 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2289 if (blwf)
2291 if (!modern)
2292 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2294 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2297 if (half)
2298 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2299 if (pstf)
2301 TRACE("applying feature pstf\n");
2302 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2304 if (vatu)
2306 TRACE("applying feature vatu\n");
2307 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2309 if (cjct)
2311 TRACE("applying feature cjct\n");
2312 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2315 if (second_reorder)
2316 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2318 overall_shift += glyph_indexs.end - old_end;
2322 static inline int unicode_lex(WCHAR c)
2324 int type;
2326 if (!c) return lex_Generic;
2327 if (c == 0x200D) return lex_ZWJ;
2328 if (c == 0x200C) return lex_ZWNJ;
2329 if (c == 0x00A0) return lex_NBSP;
2331 type = get_table_entry( indic_syllabic_table, c );
2333 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2335 switch( type )
2337 case 0x0d07: /* Unknown */
2338 case 0x0e07: /* Unknwon */
2339 default: return lex_Generic;
2340 case 0x0001:
2341 case 0x0002:
2342 case 0x0011:
2343 case 0x0012:
2344 case 0x0013:
2345 case 0x0014: return lex_Modifier;
2346 case 0x0003:
2347 case 0x0009:
2348 case 0x000a:
2349 case 0x000b:
2350 case 0x000d:
2351 case 0x000e:
2352 case 0x000f:
2353 case 0x0010: return lex_Consonant;
2354 case 0x0004: return lex_Nukta;
2355 case 0x0005: return lex_Halant;
2356 case 0x0006:
2357 case 0x0008: return lex_Vowel;
2358 case 0x0007:
2359 case 0x0107: return lex_Matra_post;
2360 case 0x0207:
2361 case 0x0307: return lex_Matra_pre;
2362 case 0x0807:
2363 case 0x0907:
2364 case 0x0a07:
2365 case 0x0b07:
2366 case 0x0c07:
2367 case 0x0407: return lex_Composed_Vowel;
2368 case 0x0507: return lex_Matra_above;
2369 case 0x0607: return lex_Matra_below;
2370 case 0x000c: return lex_Ra;
2374 static int sinhala_lex(WCHAR c)
2376 switch (c)
2378 case 0x0DDA:
2379 case 0x0DDD:
2380 case 0x0DDC:
2381 case 0x0DDE: return lex_Matra_post;
2382 default:
2383 return unicode_lex(c);
2387 static const VowelComponents Sinhala_vowels[] = {
2388 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2389 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2390 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2391 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2392 {0x0000, {0x0000,0x0000,0x0}}};
2394 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2396 int cCount = cChars;
2397 int i;
2398 WCHAR *input;
2399 IndicSyllable *syllables = NULL;
2400 int syllable_count = 0;
2402 if (*pcGlyphs != cChars)
2404 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2405 return;
2408 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2410 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2412 /* Step 1: Decompose multi part vowels */
2413 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust);
2415 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2417 /* Step 2: Reorder within Syllables */
2418 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2419 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2421 /* Step 3: Strip dangling joiners */
2422 for (i = 0; i < cCount; i++)
2424 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2425 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2426 input[i] = 0x0020;
2429 /* Step 4: Base Form application to syllables */
2430 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2431 *pcGlyphs = cCount;
2432 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2434 HeapFree(GetProcessHeap(),0,input);
2435 HeapFree(GetProcessHeap(),0,syllables);
2438 static int devanagari_lex(WCHAR c)
2440 switch (c)
2442 case 0x0930: return lex_Ra;
2443 default:
2444 return unicode_lex(c);
2448 static const ConsonantComponents Devanagari_consonants[] ={
2449 {{0x0928, 0x093C, 0x00000}, 0x0929},
2450 {{0x0930, 0x093C, 0x00000}, 0x0931},
2451 {{0x0933, 0x093C, 0x00000}, 0x0934},
2452 {{0x0915, 0x093C, 0x00000}, 0x0958},
2453 {{0x0916, 0x093C, 0x00000}, 0x0959},
2454 {{0x0917, 0x093C, 0x00000}, 0x095A},
2455 {{0x091C, 0x093C, 0x00000}, 0x095B},
2456 {{0x0921, 0x093C, 0x00000}, 0x095C},
2457 {{0x0922, 0x093C, 0x00000}, 0x095D},
2458 {{0x092B, 0x093C, 0x00000}, 0x095E},
2459 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2461 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2463 int cCount = cChars;
2464 WCHAR *input;
2465 IndicSyllable *syllables = NULL;
2466 int syllable_count = 0;
2467 BOOL modern = get_GSUB_Indic2(psa, psc);
2469 if (*pcGlyphs != cChars)
2471 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2472 return;
2475 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2476 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2478 /* Step 1: Compose Consonant and Nukta */
2479 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2480 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2482 /* Step 2: Reorder within Syllables */
2483 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2484 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2485 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2486 *pcGlyphs = cCount;
2488 /* Step 3: Base Form application to syllables */
2489 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2491 HeapFree(GetProcessHeap(),0,input);
2492 HeapFree(GetProcessHeap(),0,syllables);
2495 static int bengali_lex(WCHAR c)
2497 switch (c)
2499 case 0x09B0: return lex_Ra;
2500 default:
2501 return unicode_lex(c);
2505 static const VowelComponents Bengali_vowels[] = {
2506 {0x09CB, {0x09C7,0x09BE,0x0000}},
2507 {0x09CC, {0x09C7,0x09D7,0x0000}},
2508 {0x0000, {0x0000,0x0000,0x0000}}};
2510 static const ConsonantComponents Bengali_consonants[] = {
2511 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2512 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2513 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2514 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2515 {{0x0000,0x0000,0x0000}, 0x0000}};
2517 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2519 int cCount = cChars;
2520 WCHAR *input;
2521 IndicSyllable *syllables = NULL;
2522 int syllable_count = 0;
2523 BOOL modern = get_GSUB_Indic2(psa, psc);
2525 if (*pcGlyphs != cChars)
2527 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2528 return;
2531 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2532 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2534 /* Step 1: Decompose Vowels and Compose Consonents */
2535 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust);
2536 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2537 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2539 /* Step 2: Reorder within Syllables */
2540 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2541 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2542 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2543 *pcGlyphs = cCount;
2545 /* Step 3: Initial form is only applied to the beginning of words */
2546 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2548 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2550 int index = cCount;
2551 int gCount = 1;
2552 if (index > 0) index++;
2554 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2558 /* Step 4: Base Form application to syllables */
2559 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2561 HeapFree(GetProcessHeap(),0,input);
2562 HeapFree(GetProcessHeap(),0,syllables);
2565 static int gurmukhi_lex(WCHAR c)
2567 return unicode_lex(c);
2570 static const ConsonantComponents Gurmukhi_consonants[] = {
2571 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2572 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2573 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2574 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2575 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2576 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2577 {{0x0000,0x0000,0x0000}, 0x0000}};
2579 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2581 int cCount = cChars;
2582 WCHAR *input;
2583 IndicSyllable *syllables = NULL;
2584 int syllable_count = 0;
2585 BOOL modern = get_GSUB_Indic2(psa, psc);
2587 if (*pcGlyphs != cChars)
2589 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2590 return;
2593 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2594 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2596 /* Step 1: Compose Consonents */
2597 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2598 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2600 /* Step 2: Reorder within Syllables */
2601 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2602 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2603 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2604 *pcGlyphs = cCount;
2606 /* Step 3: Base Form application to syllables */
2607 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2609 HeapFree(GetProcessHeap(),0,input);
2610 HeapFree(GetProcessHeap(),0,syllables);
2613 static int gujarati_lex(WCHAR c)
2615 switch (c)
2617 case 0x0AB0: return lex_Ra;
2618 default:
2619 return unicode_lex(c);
2623 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2625 int cCount = cChars;
2626 WCHAR *input;
2627 IndicSyllable *syllables = NULL;
2628 int syllable_count = 0;
2629 BOOL modern = get_GSUB_Indic2(psa, psc);
2631 if (*pcGlyphs != cChars)
2633 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2634 return;
2637 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2638 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2640 /* Step 1: Reorder within Syllables */
2641 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2642 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2643 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2644 *pcGlyphs = cCount;
2646 /* Step 2: Base Form application to syllables */
2647 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2649 HeapFree(GetProcessHeap(),0,input);
2650 HeapFree(GetProcessHeap(),0,syllables);
2653 static int oriya_lex(WCHAR c)
2655 switch (c)
2657 case 0x0B30: return lex_Ra;
2658 default:
2659 return unicode_lex(c);
2663 static const VowelComponents Oriya_vowels[] = {
2664 {0x0B48, {0x0B47,0x0B56,0x0000}},
2665 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2666 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2667 {0x0000, {0x0000,0x0000,0x0000}}};
2669 static const ConsonantComponents Oriya_consonants[] = {
2670 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2671 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2672 {{0x0000,0x0000,0x0000}, 0x0000}};
2674 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2676 int cCount = cChars;
2677 WCHAR *input;
2678 IndicSyllable *syllables = NULL;
2679 int syllable_count = 0;
2680 BOOL modern = get_GSUB_Indic2(psa, psc);
2682 if (*pcGlyphs != cChars)
2684 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2685 return;
2688 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2689 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2691 /* Step 1: Decompose Vowels and Compose Consonents */
2692 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust);
2693 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2694 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2696 /* Step 2: Reorder within Syllables */
2697 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2698 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2699 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2700 *pcGlyphs = cCount;
2702 /* Step 3: Base Form application to syllables */
2703 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2705 HeapFree(GetProcessHeap(),0,input);
2706 HeapFree(GetProcessHeap(),0,syllables);
2709 static int tamil_lex(WCHAR c)
2711 return unicode_lex(c);
2714 static const VowelComponents Tamil_vowels[] = {
2715 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2716 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2717 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2718 {0x0000, {0x0000,0x0000,0x0000}}};
2720 static const ConsonantComponents Tamil_consonants[] = {
2721 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2722 {{0x0000,0x0000,0x0000}, 0x0000}};
2724 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2726 int cCount = cChars;
2727 WCHAR *input;
2728 IndicSyllable *syllables = NULL;
2729 int syllable_count = 0;
2730 BOOL modern = get_GSUB_Indic2(psa, psc);
2732 if (*pcGlyphs != cChars)
2734 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2735 return;
2738 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2739 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2741 /* Step 1: Decompose Vowels and Compose Consonents */
2742 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust);
2743 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2744 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2746 /* Step 2: Reorder within Syllables */
2747 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2748 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2749 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2750 *pcGlyphs = cCount;
2752 /* Step 3: Base Form application to syllables */
2753 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2755 HeapFree(GetProcessHeap(),0,input);
2756 HeapFree(GetProcessHeap(),0,syllables);
2759 static int telugu_lex(WCHAR c)
2761 switch (c)
2763 case 0x0C43:
2764 case 0x0C44: return lex_Modifier;
2765 default:
2766 return unicode_lex(c);
2770 static const VowelComponents Telugu_vowels[] = {
2771 {0x0C48, {0x0C46,0x0C56,0x0000}},
2772 {0x0000, {0x0000,0x0000,0x0000}}};
2774 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2776 int cCount = cChars;
2777 WCHAR *input;
2778 IndicSyllable *syllables = NULL;
2779 int syllable_count = 0;
2780 BOOL modern = get_GSUB_Indic2(psa, psc);
2782 if (*pcGlyphs != cChars)
2784 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2785 return;
2788 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2789 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2791 /* Step 1: Decompose Vowels */
2792 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust);
2793 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2795 /* Step 2: Reorder within Syllables */
2796 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2797 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2798 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2799 *pcGlyphs = cCount;
2801 /* Step 3: Base Form application to syllables */
2802 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2804 HeapFree(GetProcessHeap(),0,input);
2805 HeapFree(GetProcessHeap(),0,syllables);
2808 static int kannada_lex(WCHAR c)
2810 switch (c)
2812 case 0x0CB0: return lex_Ra;
2813 default:
2814 return unicode_lex(c);
2818 static const VowelComponents Kannada_vowels[] = {
2819 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2820 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2821 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2822 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2823 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2824 {0x0000, {0x0000,0x0000,0x0000}}};
2826 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2828 int cCount = cChars;
2829 WCHAR *input;
2830 IndicSyllable *syllables = NULL;
2831 int syllable_count = 0;
2832 BOOL modern = get_GSUB_Indic2(psa, psc);
2834 if (*pcGlyphs != cChars)
2836 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2837 return;
2840 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2841 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2843 /* Step 1: Decompose Vowels */
2844 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust);
2845 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2847 /* Step 2: Reorder within Syllables */
2848 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2849 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2850 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2851 *pcGlyphs = cCount;
2853 /* Step 3: Base Form application to syllables */
2854 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2856 HeapFree(GetProcessHeap(),0,input);
2857 HeapFree(GetProcessHeap(),0,syllables);
2860 static int malayalam_lex(WCHAR c)
2862 return unicode_lex(c);
2865 static const VowelComponents Malayalam_vowels[] = {
2866 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2867 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2868 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2869 {0x0000, {0x0000,0x0000,0x0000}}};
2871 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2873 int cCount = cChars;
2874 WCHAR *input;
2875 IndicSyllable *syllables = NULL;
2876 int syllable_count = 0;
2877 BOOL modern = get_GSUB_Indic2(psa, psc);
2879 if (*pcGlyphs != cChars)
2881 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2882 return;
2885 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2886 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2888 /* Step 1: Decompose Vowels */
2889 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust);
2890 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2892 /* Step 2: Reorder within Syllables */
2893 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2894 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2895 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2896 *pcGlyphs = cCount;
2898 /* Step 3: Base Form application to syllables */
2899 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2901 HeapFree(GetProcessHeap(),0,input);
2902 HeapFree(GetProcessHeap(),0,syllables);
2905 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
2907 int i,k;
2909 for (i = 0; i < cGlyphs; i++)
2911 int char_index[20];
2912 int char_count = 0;
2914 for (k = 0; k < cChars; k++)
2916 if (pwLogClust[k] == i)
2918 char_index[char_count] = k;
2919 char_count++;
2923 if (char_count == 0)
2925 FIXME("No chars in this glyph? Must be an error\n");
2926 continue;
2929 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2931 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2932 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2934 else
2935 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2938 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2939 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2942 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
2944 int i,k;
2945 int initGlyph, finaGlyph;
2946 INT dirR, dirL;
2947 BYTE *spaces;
2949 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2950 memset(spaces,0,cGlyphs);
2952 if (!psa->fLogicalOrder && psa->fRTL)
2954 initGlyph = cGlyphs-1;
2955 finaGlyph = 0;
2956 dirR = 1;
2957 dirL = -1;
2959 else
2961 initGlyph = 0;
2962 finaGlyph = cGlyphs-1;
2963 dirR = -1;
2964 dirL = 1;
2967 for (i = 0; i < cGlyphs; i++)
2969 for (k = 0; k < cChars; k++)
2970 if (pwLogClust[k] == i)
2972 if (pwcChars[k] == 0x0020)
2973 spaces[i] = 1;
2977 for (i = 0; i < cGlyphs; i++)
2979 int char_index[20];
2980 int char_count = 0;
2981 BOOL isInit, isFinal;
2983 for (k = 0; k < cChars; k++)
2985 if (pwLogClust[k] == i)
2987 char_index[char_count] = k;
2988 char_count++;
2992 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2993 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2995 if (char_count == 0)
2997 FIXME("No chars in this glyph? Must be an error\n");
2998 continue;
3001 if (char_count == 1)
3003 if (pwcChars[char_index[0]] == 0x0020) /* space */
3005 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3006 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3008 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3009 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3010 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3012 if (!isInit && !isFinal)
3013 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3014 else if (isInit)
3015 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3016 else
3017 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3019 else if (!isInit)
3021 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3022 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3023 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3024 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3025 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3026 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3027 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3029 else
3030 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3032 else if (!isInit && !isFinal)
3033 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3034 else
3035 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3037 else if (char_count == 2)
3039 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3040 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3041 else if (!isInit)
3042 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3043 else
3044 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3046 else if (!isInit && !isFinal)
3047 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3048 else
3049 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3052 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3053 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3054 HeapFree(GetProcessHeap(),0,spaces);
3057 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3059 int i,k;
3060 int finaGlyph;
3061 INT dirL;
3062 BYTE *spaces;
3064 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3065 memset(spaces,0,cGlyphs);
3067 if (!psa->fLogicalOrder && psa->fRTL)
3069 finaGlyph = 0;
3070 dirL = -1;
3072 else
3074 finaGlyph = cGlyphs-1;
3075 dirL = 1;
3078 for (i = 0; i < cGlyphs; i++)
3080 for (k = 0; k < cChars; k++)
3081 if (pwLogClust[k] == i)
3083 if (pwcChars[k] == 0x0020)
3084 spaces[i] = 1;
3088 for (i = 0; i < cGlyphs; i++)
3090 int char_index[20];
3091 int char_count = 0;
3093 for (k = 0; k < cChars; k++)
3095 if (pwLogClust[k] == i)
3097 char_index[char_count] = k;
3098 char_count++;
3102 if (char_count == 0)
3104 FIXME("No chars in this glyph? Must be an error\n");
3105 continue;
3108 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3110 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3111 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3113 else if (i == finaGlyph)
3114 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3115 else
3116 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3119 HeapFree(GetProcessHeap(),0,spaces);
3120 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3121 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3123 /* Do not allow justification between marks and their base */
3124 for (i = 0; i < cGlyphs; i++)
3126 if (!pGlyphProp[i].sva.fClusterStart)
3127 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3131 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
3133 int i,k;
3135 for (i = 0; i < cGlyphs; i++)
3137 int char_index[20];
3138 int char_count = 0;
3140 for (k = 0; k < cChars; k++)
3142 if (pwLogClust[k] == i)
3144 char_index[char_count] = k;
3145 char_count++;
3149 if (char_count == 0)
3151 FIXME("No chars in this glyph? Must be an error\n");
3152 continue;
3155 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3157 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3158 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3160 else
3161 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3163 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3164 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3167 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp)
3169 int i,k;
3171 for (i = 0; i < cGlyphs; i++)
3173 int char_index[20];
3174 int char_count = 0;
3176 for (k = 0; k < cChars; k++)
3178 if (pwLogClust[k] == i)
3180 char_index[char_count] = k;
3181 char_count++;
3185 if (char_count == 0)
3187 FIXME("No chars in this glyph? Must be an error\n");
3188 continue;
3191 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3193 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3194 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3196 else
3197 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3199 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3200 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3202 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3203 for (i = 0; i < cGlyphs; i++)
3205 if (!pGlyphProp[i].sva.fClusterStart)
3207 pGlyphProp[i].sva.fDiacritic = 0;
3208 pGlyphProp[i].sva.fZeroWidth = 0;
3213 static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical)
3215 int i,k;
3217 for (i = 0; i < cGlyphs; i++)
3219 int char_index[20];
3220 int char_count = 0;
3222 for (k = 0; k < cChars; k++)
3224 if (pwLogClust[k] == i)
3226 char_index[char_count] = k;
3227 char_count++;
3231 if (char_count == 0)
3233 FIXME("No chars in this glyph? Must be an error\n");
3234 continue;
3237 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3239 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3240 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3242 else
3243 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3245 pGlyphProp[i].sva.fClusterStart = 0;
3246 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3247 switch (lexical(pwcChars[char_index[k]]))
3249 case lex_Matra_pre:
3250 case lex_Matra_post:
3251 case lex_Matra_above:
3252 case lex_Matra_below:
3253 case lex_Modifier:
3254 break;
3255 default:
3256 pGlyphProp[i].sva.fClusterStart = 1;
3257 break;
3260 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3263 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3265 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3268 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3270 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3273 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3275 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3278 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3280 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3283 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3285 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3288 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3290 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3293 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3295 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3298 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3300 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3303 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3305 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3308 void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp)
3310 if (ShapingData[psa->eScript].charGlyphPropProc)
3311 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3312 else
3313 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3316 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3318 if (ShapingData[psa->eScript].contextProc)
3319 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3322 static void SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, const TEXTRANGE_PROPERTIES *rpRangeProperties, WORD *pwLogClust)
3324 int i;
3325 INT dirL;
3327 if (!rpRangeProperties)
3328 return;
3330 if (!psc->GSUB_Table)
3331 psc->GSUB_Table = load_gsub_table(hdc);
3333 if (!psc->GSUB_Table)
3334 return;
3336 if (!psa->fLogicalOrder && psa->fRTL)
3337 dirL = -1;
3338 else
3339 dirL = 1;
3341 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3343 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3344 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3348 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3350 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3351 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3353 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3356 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3358 const GSUB_Feature *feature;
3359 int i;
3361 if (!ShapingData[psa->eScript].requiredFeatures)
3362 return S_OK;
3364 if (!psc->GSUB_Table)
3365 psc->GSUB_Table = load_gsub_table(hdc);
3367 /* we need to have at least one of the required features */
3368 i = 0;
3369 while (ShapingData[psa->eScript].requiredFeatures[i])
3371 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3372 if (feature)
3373 return S_OK;
3374 i++;
3377 return USP_E_SCRIPT_NOT_IN_FONT;