usp10: When calling ShapeIndicSyllables we need to use cChars which is the actual...
[wine/multimedia.git] / dlls / usp10 / shape.c
blob499829fe2515978b8e09331e8f29fd3a08b22446
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[])
1788 int i;
1789 int cWalk;
1791 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1793 for (i = 0; vowels[i].base != 0x0; i++)
1795 if (pwOutChars[cWalk] == vowels[i].base)
1797 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1798 if (vowels[i].parts[1]) cWalk++;
1799 if (vowels[i].parts[2]) cWalk++;
1800 break;
1806 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1808 int i;
1809 int cWalk;
1811 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1813 for (i = 0; consonants[i].output!= 0x0; i++)
1815 int j;
1816 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1817 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1818 break;
1820 if (consonants[i].parts[j]==0x0) /* matched all */
1822 int k;
1823 j--;
1824 pwOutChars[cWalk] = consonants[i].output;
1825 for(k = cWalk+1; k < *pcChars - j; k++)
1826 pwOutChars[k] = pwOutChars[k+j];
1827 *pcChars = *pcChars - j;
1828 break;
1831 cWalk++;
1835 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1837 if (s->ralf >= 0)
1839 int j;
1840 WORD Ra = pwChar[s->start];
1841 WORD H = pwChar[s->start+1];
1843 TRACE("Doing reorder of Ra to %i\n",s->base);
1844 for (j = s->start; j < s->base-1; j++)
1845 pwChar[j] = pwChar[j+2];
1846 pwChar[s->base-1] = Ra;
1847 pwChar[s->base] = H;
1849 s->ralf = s->base-1;
1850 s->base -= 2;
1854 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1856 if (s->ralf >= 0)
1858 int j,loc;
1859 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1860 WORD Ra = pwChar[s->start];
1861 WORD H = pwChar[s->start+1];
1862 for (loc = s->end; loc > stop; loc--)
1863 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1864 break;
1866 TRACE("Doing reorder of Ra to %i\n",loc);
1867 for (j = s->start; j < loc-1; j++)
1868 pwChar[j] = pwChar[j+2];
1869 pwChar[loc-1] = Ra;
1870 pwChar[loc] = H;
1872 s->ralf = loc-1;
1873 s->base -= 2;
1874 if (s->blwf >= 0) s->blwf -= 2;
1875 if (s->pref >= 0) s->pref -= 2;
1879 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1881 if (s->ralf >= 0)
1883 int j;
1884 WORD Ra = pwChar[s->start];
1885 WORD H = pwChar[s->start+1];
1887 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1888 for (j = s->start; j < s->end-1; j++)
1889 pwChar[j] = pwChar[j+2];
1890 pwChar[s->end-1] = Ra;
1891 pwChar[s->end] = H;
1893 s->ralf = s->end-1;
1894 s->base -= 2;
1895 if (s->blwf >= 0) s->blwf -= 2;
1896 if (s->pref >= 0) s->pref -= 2;
1900 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1902 int i;
1904 /* reorder Matras */
1905 if (s->end > s->base)
1907 for (i = 1; i <= s->end-s->base; i++)
1909 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1911 int j;
1912 WCHAR c = pwChar[s->base+i];
1913 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1914 for (j = s->base+i; j > s->base; j--)
1915 pwChar[j] = pwChar[j-1];
1916 pwChar[s->base] = c;
1918 if (s->ralf >= s->base) s->ralf++;
1919 if (s->blwf >= s->base) s->blwf++;
1920 if (s->pref >= s->base) s->pref++;
1921 s->base ++;
1927 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1929 int i;
1931 /* reorder Matras */
1932 if (s->end > s->base)
1934 for (i = 1; i <= s->end-s->base; i++)
1936 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1938 int j;
1939 WCHAR c = pwChar[s->base+i];
1940 TRACE("Doing reorder of %x to %i\n",c,s->start);
1941 for (j = s->base+i; j > s->start; j--)
1942 pwChar[j] = pwChar[j-1];
1943 pwChar[s->start] = c;
1945 if (s->ralf >= 0) s->ralf++;
1946 if (s->blwf >= 0) s->blwf++;
1947 if (s->pref >= 0) s->pref++;
1948 s->base ++;
1954 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1956 if (s->blwf >= 0 && g->blwf > g->base)
1958 int j,loc;
1959 int g_offset;
1960 for (loc = s->end; loc > s->blwf; loc--)
1961 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1962 break;
1964 g_offset = (loc - s->blwf) - 1;
1966 if (loc != s->blwf)
1968 WORD blwf = glyphs[g->blwf];
1969 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1970 /* do not care about the pwChar array anymore, just the glyphs */
1971 for (j = 0; j < g_offset; j++)
1972 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1973 glyphs[g->blwf + g_offset] = blwf;
1978 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1980 int i;
1982 /* reorder previously moved Matras to correct position*/
1983 for (i = s->start; i < s->base; i++)
1985 if (lexical(pwChar[i]) == lex_Matra_pre)
1987 int j;
1988 int g_start = g->start + i - s->start;
1989 if (g_start < g->base -1 )
1991 WCHAR og = glyphs[g_start];
1992 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1993 for (j = g_start; j < g->base-1; j++)
1994 glyphs[j] = glyphs[j+1];
1995 glyphs[g->base-1] = og;
2001 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2003 if (s->pref >= 0 && g->pref > g->base)
2005 int j;
2006 WCHAR og = glyphs[g->pref];
2007 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2008 for (j = g->pref; j > g->base; j--)
2009 glyphs[j] = glyphs[j-1];
2010 glyphs[g->base] = og;
2014 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2016 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2017 if (s->start == s->base && s->base == s->end) return;
2018 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2020 Reorder_Ra_follows_base(pwChar, s, lexical);
2021 Reorder_Matra_precede_base(pwChar, s, lexical);
2024 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2026 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2027 if (s->start == s->base && s->base == s->end) return;
2028 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2030 Reorder_Ra_follows_matra(pwChar, s, lexical);
2031 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2034 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2036 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2037 if (s->start == s->base && s->base == s->end) return;
2038 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2040 Reorder_Ra_follows_base(pwChar, s, lexical);
2041 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2044 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2046 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2047 if (s->start == s->base && s->base == s->end) return;
2048 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2050 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2051 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2054 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2056 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2057 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2058 if (s->start == s->base && s->base == s->end) return;
2059 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2061 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2064 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2066 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2067 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2068 if (s->start == s->base && s->base == s->end) return;
2069 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2071 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2072 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2076 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2078 if (shift == 0)
2079 return;
2081 if (glyph_index->start > index)
2082 glyph_index->start += shift;
2083 if (glyph_index->base > index)
2084 glyph_index->base+= shift;
2085 if (glyph_index->end > index)
2086 glyph_index->end+= shift;
2087 if (glyph_index->ralf > index)
2088 glyph_index->ralf+= shift;
2089 if (glyph_index->blwf > index)
2090 glyph_index->blwf+= shift;
2091 if (glyph_index->pref > index)
2092 glyph_index->pref+= shift;
2095 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 )
2097 int index = glyph_index->start;
2099 if (!feature)
2100 return;
2102 while(index <= glyph_index->end)
2104 INT nextIndex;
2105 INT prevCount = *pcGlyphs;
2106 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2107 if (nextIndex > GSUB_E_NOGLYPH)
2109 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2110 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2111 index = nextIndex;
2113 else
2114 index++;
2118 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2120 int i = 0;
2121 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)))))
2122 i++;
2123 if (index + i <= end-1)
2124 return index + i;
2125 else
2126 return -1;
2129 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)
2131 INT index, nextIndex;
2132 INT count,g_offset;
2134 count = syllable->base - syllable->start;
2136 g_offset = 0;
2137 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2138 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2140 INT prevCount = *pcGlyphs;
2141 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2142 if (nextIndex > GSUB_E_NOGLYPH)
2144 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2145 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2146 g_offset += (*pcGlyphs - prevCount);
2149 index+=2;
2150 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2154 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)
2156 INT nextIndex;
2157 INT prevCount = *pcGlyphs;
2159 if (syllable->ralf >= 0)
2161 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2162 if (nextIndex > GSUB_E_NOGLYPH)
2164 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2165 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2170 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2172 int i = 0;
2173 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2174 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2175 is_consonant(lexical(pwChars[index+i+1])))))
2176 i++;
2177 if (index + i <= end-1)
2178 return index+i;
2179 else
2180 return -1;
2183 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)
2185 INT index, nextIndex;
2186 INT count, g_offset=0;
2187 INT ralf = syllable->ralf;
2189 count = syllable->end - syllable->base;
2191 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2193 while (index >= 0)
2195 INT prevCount = *pcGlyphs;
2196 if (ralf >=0 && ralf < index)
2198 g_offset--;
2199 ralf = -1;
2202 if (!modern)
2204 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2205 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2206 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2209 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2210 if (nextIndex > GSUB_E_NOGLYPH)
2212 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2213 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2214 g_offset += (*pcGlyphs - prevCount);
2216 else if (!modern)
2218 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2219 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2220 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2223 index+=2;
2224 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2228 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)
2230 int c;
2231 int overall_shift = 0;
2232 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2233 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2234 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2235 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2236 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2237 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2238 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2239 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2240 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2241 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2242 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2243 IndicSyllable glyph_indexs;
2245 for (c = 0; c < syllable_count; c++)
2247 int old_end;
2248 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2249 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2250 old_end = glyph_indexs.end;
2252 if (locl)
2254 TRACE("applying feature locl\n");
2255 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2257 if (nukt)
2259 TRACE("applying feature nukt\n");
2260 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2262 if (akhn)
2264 TRACE("applying feature akhn\n");
2265 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2268 if (rphf)
2269 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2270 if (rkrf)
2272 TRACE("applying feature rkrf\n");
2273 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2275 if (pref)
2276 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2277 if (blwf)
2279 if (!modern)
2280 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2282 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2285 if (half)
2286 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2287 if (pstf)
2289 TRACE("applying feature pstf\n");
2290 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2292 if (vatu)
2294 TRACE("applying feature vatu\n");
2295 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2297 if (cjct)
2299 TRACE("applying feature cjct\n");
2300 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2303 if (second_reorder)
2304 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2306 overall_shift += glyph_indexs.end - old_end;
2310 static inline int unicode_lex(WCHAR c)
2312 int type;
2314 if (!c) return lex_Generic;
2315 if (c == 0x200D) return lex_ZWJ;
2316 if (c == 0x200C) return lex_ZWNJ;
2317 if (c == 0x00A0) return lex_NBSP;
2319 type = get_table_entry( indic_syllabic_table, c );
2321 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2323 switch( type )
2325 case 0x0d07: /* Unknown */
2326 case 0x0e07: /* Unknwon */
2327 default: return lex_Generic;
2328 case 0x0001:
2329 case 0x0002:
2330 case 0x0011:
2331 case 0x0012:
2332 case 0x0013:
2333 case 0x0014: return lex_Modifier;
2334 case 0x0003:
2335 case 0x0009:
2336 case 0x000a:
2337 case 0x000b:
2338 case 0x000d:
2339 case 0x000e:
2340 case 0x000f:
2341 case 0x0010: return lex_Consonant;
2342 case 0x0004: return lex_Nukta;
2343 case 0x0005: return lex_Halant;
2344 case 0x0006:
2345 case 0x0008: return lex_Vowel;
2346 case 0x0007:
2347 case 0x0107: return lex_Matra_post;
2348 case 0x0207:
2349 case 0x0307: return lex_Matra_pre;
2350 case 0x0807:
2351 case 0x0907:
2352 case 0x0a07:
2353 case 0x0b07:
2354 case 0x0c07:
2355 case 0x0407: return lex_Composed_Vowel;
2356 case 0x0507: return lex_Matra_above;
2357 case 0x0607: return lex_Matra_below;
2358 case 0x000c: return lex_Ra;
2362 static int sinhala_lex(WCHAR c)
2364 switch (c)
2366 case 0x0DDA:
2367 case 0x0DDD:
2368 case 0x0DDC:
2369 case 0x0DDE: return lex_Matra_post;
2370 default:
2371 return unicode_lex(c);
2375 static const VowelComponents Sinhala_vowels[] = {
2376 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2377 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2378 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2379 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2380 {0x0000, {0x0000,0x0000,0x0}}};
2382 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2384 int cCount = cChars;
2385 int i;
2386 WCHAR *input;
2387 IndicSyllable *syllables = NULL;
2388 int syllable_count = 0;
2390 if (*pcGlyphs != cChars)
2392 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2393 return;
2396 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2398 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2400 /* Step 1: Decompose multi part vowels */
2401 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels);
2403 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2405 /* Step 2: Reorder within Syllables */
2406 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2407 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2409 /* Step 3: Strip dangling joiners */
2410 for (i = 0; i < cCount; i++)
2412 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2413 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2414 input[i] = 0x0020;
2417 /* Step 4: Base Form application to syllables */
2418 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2419 *pcGlyphs = cCount;
2420 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2422 HeapFree(GetProcessHeap(),0,input);
2423 HeapFree(GetProcessHeap(),0,syllables);
2426 static int devanagari_lex(WCHAR c)
2428 switch (c)
2430 case 0x0930: return lex_Ra;
2431 default:
2432 return unicode_lex(c);
2436 static const ConsonantComponents Devanagari_consonants[] ={
2437 {{0x0928, 0x093C, 0x00000}, 0x0929},
2438 {{0x0930, 0x093C, 0x00000}, 0x0931},
2439 {{0x0933, 0x093C, 0x00000}, 0x0934},
2440 {{0x0915, 0x093C, 0x00000}, 0x0958},
2441 {{0x0916, 0x093C, 0x00000}, 0x0959},
2442 {{0x0917, 0x093C, 0x00000}, 0x095A},
2443 {{0x091C, 0x093C, 0x00000}, 0x095B},
2444 {{0x0921, 0x093C, 0x00000}, 0x095C},
2445 {{0x0922, 0x093C, 0x00000}, 0x095D},
2446 {{0x092B, 0x093C, 0x00000}, 0x095E},
2447 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2449 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2451 int cCount = cChars;
2452 WCHAR *input;
2453 IndicSyllable *syllables = NULL;
2454 int syllable_count = 0;
2455 BOOL modern = get_GSUB_Indic2(psa, psc);
2457 if (*pcGlyphs != cChars)
2459 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2460 return;
2463 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2464 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2466 /* Step 1: Compose Consonant and Nukta */
2467 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2468 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2470 /* Step 2: Reorder within Syllables */
2471 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2472 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2473 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2474 *pcGlyphs = cCount;
2476 /* Step 3: Base Form application to syllables */
2477 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2479 HeapFree(GetProcessHeap(),0,input);
2480 HeapFree(GetProcessHeap(),0,syllables);
2483 static int bengali_lex(WCHAR c)
2485 switch (c)
2487 case 0x09B0: return lex_Ra;
2488 default:
2489 return unicode_lex(c);
2493 static const VowelComponents Bengali_vowels[] = {
2494 {0x09CB, {0x09C7,0x09BE,0x0000}},
2495 {0x09CC, {0x09C7,0x09D7,0x0000}},
2496 {0x0000, {0x0000,0x0000,0x0000}}};
2498 static const ConsonantComponents Bengali_consonants[] = {
2499 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2500 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2501 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2502 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2503 {{0x0000,0x0000,0x0000}, 0x0000}};
2505 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2507 int cCount = cChars;
2508 WCHAR *input;
2509 IndicSyllable *syllables = NULL;
2510 int syllable_count = 0;
2511 BOOL modern = get_GSUB_Indic2(psa, psc);
2513 if (*pcGlyphs != cChars)
2515 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2516 return;
2519 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2520 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2522 /* Step 1: Decompose Vowels and Compose Consonents */
2523 DecomposeVowels(hdc, input, &cCount, Bengali_vowels);
2524 ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2525 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2527 /* Step 2: Reorder within Syllables */
2528 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2529 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2530 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2531 *pcGlyphs = cCount;
2533 /* Step 3: Initial form is only applied to the beginning of words */
2534 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2536 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2538 int index = cCount;
2539 int gCount = 1;
2540 if (index > 0) index++;
2542 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2546 /* Step 4: Base Form application to syllables */
2547 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2549 HeapFree(GetProcessHeap(),0,input);
2550 HeapFree(GetProcessHeap(),0,syllables);
2553 static int gurmukhi_lex(WCHAR c)
2555 return unicode_lex(c);
2558 static const ConsonantComponents Gurmukhi_consonants[] = {
2559 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2560 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2561 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2562 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2563 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2564 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2565 {{0x0000,0x0000,0x0000}, 0x0000}};
2567 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2569 int cCount = cChars;
2570 WCHAR *input;
2571 IndicSyllable *syllables = NULL;
2572 int syllable_count = 0;
2573 BOOL modern = get_GSUB_Indic2(psa, psc);
2575 if (*pcGlyphs != cChars)
2577 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2578 return;
2581 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2582 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2584 /* Step 1: Compose Consonents */
2585 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2586 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2588 /* Step 2: Reorder within Syllables */
2589 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2590 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2591 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2592 *pcGlyphs = cCount;
2594 /* Step 3: Base Form application to syllables */
2595 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2597 HeapFree(GetProcessHeap(),0,input);
2598 HeapFree(GetProcessHeap(),0,syllables);
2601 static int gujarati_lex(WCHAR c)
2603 switch (c)
2605 case 0x0AB0: return lex_Ra;
2606 default:
2607 return unicode_lex(c);
2611 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2613 int cCount = cChars;
2614 WCHAR *input;
2615 IndicSyllable *syllables = NULL;
2616 int syllable_count = 0;
2617 BOOL modern = get_GSUB_Indic2(psa, psc);
2619 if (*pcGlyphs != cChars)
2621 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2622 return;
2625 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2626 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2628 /* Step 1: Reorder within Syllables */
2629 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2630 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2631 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2632 *pcGlyphs = cCount;
2634 /* Step 2: Base Form application to syllables */
2635 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2637 HeapFree(GetProcessHeap(),0,input);
2638 HeapFree(GetProcessHeap(),0,syllables);
2641 static int oriya_lex(WCHAR c)
2643 switch (c)
2645 case 0x0B30: return lex_Ra;
2646 default:
2647 return unicode_lex(c);
2651 static const VowelComponents Oriya_vowels[] = {
2652 {0x0B48, {0x0B47,0x0B56,0x0000}},
2653 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2654 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2655 {0x0000, {0x0000,0x0000,0x0000}}};
2657 static const ConsonantComponents Oriya_consonants[] = {
2658 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2659 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2660 {{0x0000,0x0000,0x0000}, 0x0000}};
2662 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2664 int cCount = cChars;
2665 WCHAR *input;
2666 IndicSyllable *syllables = NULL;
2667 int syllable_count = 0;
2668 BOOL modern = get_GSUB_Indic2(psa, psc);
2670 if (*pcGlyphs != cChars)
2672 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2673 return;
2676 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2677 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2679 /* Step 1: Decompose Vowels and Compose Consonents */
2680 DecomposeVowels(hdc, input, &cCount, Oriya_vowels);
2681 ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2682 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2684 /* Step 2: Reorder within Syllables */
2685 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2686 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2687 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2688 *pcGlyphs = cCount;
2690 /* Step 3: Base Form application to syllables */
2691 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2693 HeapFree(GetProcessHeap(),0,input);
2694 HeapFree(GetProcessHeap(),0,syllables);
2697 static int tamil_lex(WCHAR c)
2699 return unicode_lex(c);
2702 static const VowelComponents Tamil_vowels[] = {
2703 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2704 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2705 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2706 {0x0000, {0x0000,0x0000,0x0000}}};
2708 static const ConsonantComponents Tamil_consonants[] = {
2709 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2710 {{0x0000,0x0000,0x0000}, 0x0000}};
2712 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2714 int cCount = cChars;
2715 WCHAR *input;
2716 IndicSyllable *syllables = NULL;
2717 int syllable_count = 0;
2718 BOOL modern = get_GSUB_Indic2(psa, psc);
2720 if (*pcGlyphs != cChars)
2722 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2723 return;
2726 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2727 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2729 /* Step 1: Decompose Vowels and Compose Consonents */
2730 DecomposeVowels(hdc, input, &cCount, Tamil_vowels);
2731 ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2732 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2734 /* Step 2: Reorder within Syllables */
2735 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2736 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2737 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2738 *pcGlyphs = cCount;
2740 /* Step 3: Base Form application to syllables */
2741 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2743 HeapFree(GetProcessHeap(),0,input);
2744 HeapFree(GetProcessHeap(),0,syllables);
2747 static int telugu_lex(WCHAR c)
2749 switch (c)
2751 case 0x0C43:
2752 case 0x0C44: return lex_Modifier;
2753 default:
2754 return unicode_lex(c);
2758 static const VowelComponents Telugu_vowels[] = {
2759 {0x0C48, {0x0C46,0x0C56,0x0000}},
2760 {0x0000, {0x0000,0x0000,0x0000}}};
2762 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2764 int cCount = cChars;
2765 WCHAR *input;
2766 IndicSyllable *syllables = NULL;
2767 int syllable_count = 0;
2768 BOOL modern = get_GSUB_Indic2(psa, psc);
2770 if (*pcGlyphs != cChars)
2772 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2773 return;
2776 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2777 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2779 /* Step 1: Decompose Vowels */
2780 DecomposeVowels(hdc, input, &cCount, Telugu_vowels);
2781 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2783 /* Step 2: Reorder within Syllables */
2784 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2785 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2786 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2787 *pcGlyphs = cCount;
2789 /* Step 3: Base Form application to syllables */
2790 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2792 HeapFree(GetProcessHeap(),0,input);
2793 HeapFree(GetProcessHeap(),0,syllables);
2796 static int kannada_lex(WCHAR c)
2798 switch (c)
2800 case 0x0CB0: return lex_Ra;
2801 default:
2802 return unicode_lex(c);
2806 static const VowelComponents Kannada_vowels[] = {
2807 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2808 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2809 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2810 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2811 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2812 {0x0000, {0x0000,0x0000,0x0000}}};
2814 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2816 int cCount = cChars;
2817 WCHAR *input;
2818 IndicSyllable *syllables = NULL;
2819 int syllable_count = 0;
2820 BOOL modern = get_GSUB_Indic2(psa, psc);
2822 if (*pcGlyphs != cChars)
2824 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2825 return;
2828 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2829 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2831 /* Step 1: Decompose Vowels */
2832 DecomposeVowels(hdc, input, &cCount, Kannada_vowels);
2833 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2835 /* Step 2: Reorder within Syllables */
2836 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2837 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2838 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2839 *pcGlyphs = cCount;
2841 /* Step 3: Base Form application to syllables */
2842 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2844 HeapFree(GetProcessHeap(),0,input);
2845 HeapFree(GetProcessHeap(),0,syllables);
2848 static int malayalam_lex(WCHAR c)
2850 return unicode_lex(c);
2853 static const VowelComponents Malayalam_vowels[] = {
2854 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2855 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2856 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2857 {0x0000, {0x0000,0x0000,0x0000}}};
2859 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2861 int cCount = cChars;
2862 WCHAR *input;
2863 IndicSyllable *syllables = NULL;
2864 int syllable_count = 0;
2865 BOOL modern = get_GSUB_Indic2(psa, psc);
2867 if (*pcGlyphs != cChars)
2869 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2870 return;
2873 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2874 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2876 /* Step 1: Decompose Vowels */
2877 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels);
2878 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2880 /* Step 2: Reorder within Syllables */
2881 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2882 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2883 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2884 *pcGlyphs = cCount;
2886 /* Step 3: Base Form application to syllables */
2887 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2889 HeapFree(GetProcessHeap(),0,input);
2890 HeapFree(GetProcessHeap(),0,syllables);
2893 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)
2895 int i,k;
2897 for (i = 0; i < cGlyphs; i++)
2899 int char_index[20];
2900 int char_count = 0;
2902 for (k = 0; k < cChars; k++)
2904 if (pwLogClust[k] == i)
2906 char_index[char_count] = k;
2907 char_count++;
2911 if (char_count == 0)
2913 FIXME("No chars in this glyph? Must be an error\n");
2914 continue;
2917 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2919 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2920 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2922 else
2923 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2926 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2927 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2930 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 )
2932 int i,k;
2933 int initGlyph, finaGlyph;
2934 INT dirR, dirL;
2935 BYTE *spaces;
2937 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2938 memset(spaces,0,cGlyphs);
2940 if (!psa->fLogicalOrder && psa->fRTL)
2942 initGlyph = cGlyphs-1;
2943 finaGlyph = 0;
2944 dirR = 1;
2945 dirL = -1;
2947 else
2949 initGlyph = 0;
2950 finaGlyph = cGlyphs-1;
2951 dirR = -1;
2952 dirL = 1;
2955 for (i = 0; i < cGlyphs; i++)
2957 for (k = 0; k < cChars; k++)
2958 if (pwLogClust[k] == i)
2960 if (pwcChars[k] == 0x0020)
2961 spaces[i] = 1;
2965 for (i = 0; i < cGlyphs; i++)
2967 int char_index[20];
2968 int char_count = 0;
2969 BOOL isInit, isFinal;
2971 for (k = 0; k < cChars; k++)
2973 if (pwLogClust[k] == i)
2975 char_index[char_count] = k;
2976 char_count++;
2980 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2981 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2983 if (char_count == 0)
2985 FIXME("No chars in this glyph? Must be an error\n");
2986 continue;
2989 if (char_count == 1)
2991 if (pwcChars[char_index[0]] == 0x0020) /* space */
2993 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2994 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2996 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2997 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2998 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3000 if (!isInit && !isFinal)
3001 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3002 else if (isInit)
3003 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3004 else
3005 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3007 else if (!isInit)
3009 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3010 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3011 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3012 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3013 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3014 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3015 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3016 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3017 else
3018 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3020 else if (!isInit && !isFinal)
3021 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3022 else
3023 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3025 else if (char_count == 2)
3027 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3029 else if (!isInit)
3030 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3031 else
3032 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3034 else if (!isInit && !isFinal)
3035 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3036 else
3037 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3040 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3041 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3042 HeapFree(GetProcessHeap(),0,spaces);
3045 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 )
3047 int i,k;
3048 int finaGlyph;
3049 INT dirL;
3050 BYTE *spaces;
3052 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3053 memset(spaces,0,cGlyphs);
3055 if (!psa->fLogicalOrder && psa->fRTL)
3057 finaGlyph = 0;
3058 dirL = -1;
3060 else
3062 finaGlyph = cGlyphs-1;
3063 dirL = 1;
3066 for (i = 0; i < cGlyphs; i++)
3068 for (k = 0; k < cChars; k++)
3069 if (pwLogClust[k] == i)
3071 if (pwcChars[k] == 0x0020)
3072 spaces[i] = 1;
3076 for (i = 0; i < cGlyphs; i++)
3078 int char_index[20];
3079 int char_count = 0;
3081 for (k = 0; k < cChars; k++)
3083 if (pwLogClust[k] == i)
3085 char_index[char_count] = k;
3086 char_count++;
3090 if (char_count == 0)
3092 FIXME("No chars in this glyph? Must be an error\n");
3093 continue;
3096 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3098 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3099 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3101 else if (i == finaGlyph)
3102 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3103 else
3104 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3107 HeapFree(GetProcessHeap(),0,spaces);
3108 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3109 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3111 /* Do not allow justification between marks and their base */
3112 for (i = 0; i < cGlyphs; i++)
3114 if (!pGlyphProp[i].sva.fClusterStart)
3115 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3119 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)
3121 int i,k;
3123 for (i = 0; i < cGlyphs; i++)
3125 int char_index[20];
3126 int char_count = 0;
3128 for (k = 0; k < cChars; k++)
3130 if (pwLogClust[k] == i)
3132 char_index[char_count] = k;
3133 char_count++;
3137 if (char_count == 0)
3139 FIXME("No chars in this glyph? Must be an error\n");
3140 continue;
3143 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3145 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3146 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3148 else
3149 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3151 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3152 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3155 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)
3157 int i,k;
3159 for (i = 0; i < cGlyphs; i++)
3161 int char_index[20];
3162 int char_count = 0;
3164 for (k = 0; k < cChars; k++)
3166 if (pwLogClust[k] == i)
3168 char_index[char_count] = k;
3169 char_count++;
3173 if (char_count == 0)
3175 FIXME("No chars in this glyph? Must be an error\n");
3176 continue;
3179 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3181 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3182 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3184 else
3185 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3187 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3188 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3190 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3191 for (i = 0; i < cGlyphs; i++)
3193 if (!pGlyphProp[i].sva.fClusterStart)
3195 pGlyphProp[i].sva.fDiacritic = 0;
3196 pGlyphProp[i].sva.fZeroWidth = 0;
3201 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)
3203 int i,k;
3205 for (i = 0; i < cGlyphs; i++)
3207 int char_index[20];
3208 int char_count = 0;
3210 for (k = 0; k < cChars; k++)
3212 if (pwLogClust[k] == i)
3214 char_index[char_count] = k;
3215 char_count++;
3219 if (char_count == 0)
3221 FIXME("No chars in this glyph? Must be an error\n");
3222 continue;
3225 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3227 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3228 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3230 else
3231 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3233 pGlyphProp[i].sva.fClusterStart = 0;
3234 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3235 switch (lexical(pwcChars[char_index[k]]))
3237 case lex_Matra_pre:
3238 case lex_Matra_post:
3239 case lex_Matra_above:
3240 case lex_Matra_below:
3241 case lex_Modifier:
3242 break;
3243 default:
3244 pGlyphProp[i].sva.fClusterStart = 1;
3245 break;
3248 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3251 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 )
3253 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3256 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 )
3258 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3261 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 )
3263 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3266 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 )
3268 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3271 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 )
3273 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3276 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 )
3278 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3281 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 )
3283 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3286 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 )
3288 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3291 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 )
3293 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3296 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)
3298 if (ShapingData[psa->eScript].charGlyphPropProc)
3299 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3300 else
3301 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3304 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3306 if (ShapingData[psa->eScript].contextProc)
3307 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3310 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)
3312 int i;
3313 INT dirL;
3315 if (!rpRangeProperties)
3316 return;
3318 if (!psc->GSUB_Table)
3319 psc->GSUB_Table = load_gsub_table(hdc);
3321 if (!psc->GSUB_Table)
3322 return;
3324 if (!psa->fLogicalOrder && psa->fRTL)
3325 dirL = -1;
3326 else
3327 dirL = 1;
3329 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3331 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3332 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3336 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3338 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3339 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3341 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3344 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3346 const GSUB_Feature *feature;
3347 int i;
3349 if (!ShapingData[psa->eScript].requiredFeatures)
3350 return S_OK;
3352 if (!psc->GSUB_Table)
3353 psc->GSUB_Table = load_gsub_table(hdc);
3355 /* we need to have at least one of the required features */
3356 i = 0;
3357 while (ShapingData[psa->eScript].requiredFeatures[i])
3359 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3360 if (feature)
3361 return S_OK;
3362 i++;
3365 return USP_E_SCRIPT_NOT_IN_FONT;