usp10: Windows breaks punctuation into 2 different script types.
[wine.git] / dlls / usp10 / shape.c
blobdd4d23bd390a27889264693f9d382e58d48882d8
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_Sinhala( 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_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 );
66 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 );
67 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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
75 extern const unsigned short indic_syllabic_table[];
76 extern const unsigned short wine_shaping_table[];
77 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
79 enum joining_types {
80 jtU,
81 jtT,
82 jtR,
83 jtL,
84 jtD,
85 jtC
88 enum joined_forms {
89 Xn=0,
90 Xr,
91 Xl,
92 Xm,
93 /* Syriac Alaph */
94 Afj,
95 Afn,
96 Afx
99 #ifdef WORDS_BIGENDIAN
100 #define GET_BE_WORD(x) (x)
101 #else
102 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
103 #endif
105 /* These are all structures needed for the GSUB table */
106 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
107 #define GSUB_E_NOFEATURE -2
108 #define GSUB_E_NOGLYPH -1
110 typedef struct {
111 DWORD version;
112 WORD ScriptList;
113 WORD FeatureList;
114 WORD LookupList;
115 } GSUB_Header;
117 typedef struct {
118 CHAR ScriptTag[4];
119 WORD Script;
120 } GSUB_ScriptRecord;
122 typedef struct {
123 WORD ScriptCount;
124 GSUB_ScriptRecord ScriptRecord[1];
125 } GSUB_ScriptList;
127 typedef struct {
128 CHAR LangSysTag[4];
129 WORD LangSys;
130 } GSUB_LangSysRecord;
132 typedef struct {
133 WORD DefaultLangSys;
134 WORD LangSysCount;
135 GSUB_LangSysRecord LangSysRecord[1];
136 } GSUB_Script;
138 typedef struct {
139 WORD LookupOrder; /* Reserved */
140 WORD ReqFeatureIndex;
141 WORD FeatureCount;
142 WORD FeatureIndex[1];
143 } GSUB_LangSys;
145 typedef struct {
146 CHAR FeatureTag[4];
147 WORD Feature;
148 } GSUB_FeatureRecord;
150 typedef struct {
151 WORD FeatureCount;
152 GSUB_FeatureRecord FeatureRecord[1];
153 } GSUB_FeatureList;
155 typedef struct {
156 WORD FeatureParams; /* Reserved */
157 WORD LookupCount;
158 WORD LookupListIndex[1];
159 } GSUB_Feature;
161 typedef struct {
162 WORD LookupCount;
163 WORD Lookup[1];
164 } GSUB_LookupList;
166 typedef struct {
167 WORD LookupType;
168 WORD LookupFlag;
169 WORD SubTableCount;
170 WORD SubTable[1];
171 } GSUB_LookupTable;
173 typedef struct {
174 WORD CoverageFormat;
175 WORD GlyphCount;
176 WORD GlyphArray[1];
177 } GSUB_CoverageFormat1;
179 typedef struct {
180 WORD Start;
181 WORD End;
182 WORD StartCoverageIndex;
183 } GSUB_RangeRecord;
185 typedef struct {
186 WORD CoverageFormat;
187 WORD RangeCount;
188 GSUB_RangeRecord RangeRecord[1];
189 } GSUB_CoverageFormat2;
191 typedef struct {
192 WORD SubstFormat; /* = 1 */
193 WORD Coverage;
194 WORD DeltaGlyphID;
195 } GSUB_SingleSubstFormat1;
197 typedef struct {
198 WORD SubstFormat; /* = 2 */
199 WORD Coverage;
200 WORD GlyphCount;
201 WORD Substitute[1];
202 }GSUB_SingleSubstFormat2;
204 typedef struct {
205 WORD SubstFormat; /* = 1 */
206 WORD Coverage;
207 WORD SequenceCount;
208 WORD Sequence[1];
209 }GSUB_MultipleSubstFormat1;
211 typedef struct {
212 WORD GlyphCount;
213 WORD Substitute[1];
214 }GSUB_Sequence;
216 typedef struct {
217 WORD SubstFormat; /* = 1 */
218 WORD Coverage;
219 WORD LigSetCount;
220 WORD LigatureSet[1];
221 }GSUB_LigatureSubstFormat1;
223 typedef struct {
224 WORD LigatureCount;
225 WORD Ligature[1];
226 }GSUB_LigatureSet;
228 typedef struct{
229 WORD LigGlyph;
230 WORD CompCount;
231 WORD Component[1];
232 }GSUB_Ligature;
234 typedef struct{
235 WORD SequenceIndex;
236 WORD LookupListIndex;
238 }GSUB_SubstLookupRecord;
240 typedef struct{
241 WORD SubstFormat; /* = 1 */
242 WORD Coverage;
243 WORD ChainSubRuleSetCount;
244 WORD ChainSubRuleSet[1];
245 }GSUB_ChainContextSubstFormat1;
247 typedef struct {
248 WORD SubstFormat; /* = 3 */
249 WORD BacktrackGlyphCount;
250 WORD Coverage[1];
251 }GSUB_ChainContextSubstFormat3_1;
253 typedef struct{
254 WORD InputGlyphCount;
255 WORD Coverage[1];
256 }GSUB_ChainContextSubstFormat3_2;
258 typedef struct{
259 WORD LookaheadGlyphCount;
260 WORD Coverage[1];
261 }GSUB_ChainContextSubstFormat3_3;
263 typedef struct{
264 WORD SubstCount;
265 GSUB_SubstLookupRecord SubstLookupRecord[1];
266 }GSUB_ChainContextSubstFormat3_4;
268 typedef struct {
269 WORD SubstFormat; /* = 1 */
270 WORD Coverage;
271 WORD AlternateSetCount;
272 WORD AlternateSet[1];
273 } GSUB_AlternateSubstFormat1;
275 typedef struct{
276 WORD GlyphCount;
277 WORD Alternate[1];
278 } GSUB_AlternateSet;
280 /* These are all structures needed for the GDEF table */
281 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
283 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
285 typedef struct {
286 DWORD Version;
287 WORD GlyphClassDef;
288 WORD AttachList;
289 WORD LigCaretList;
290 WORD MarkAttachClassDef;
291 } GDEF_Header;
293 typedef struct {
294 WORD ClassFormat;
295 WORD StartGlyph;
296 WORD GlyphCount;
297 WORD ClassValueArray[1];
298 } GDEF_ClassDefFormat1;
300 typedef struct {
301 WORD Start;
302 WORD End;
303 WORD Class;
304 } GDEF_ClassRangeRecord;
306 typedef struct {
307 WORD ClassFormat;
308 WORD ClassRangeCount;
309 GDEF_ClassRangeRecord ClassRangeRecord[1];
310 } GDEF_ClassDefFormat2;
312 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
314 typedef struct tagVowelComponents
316 WCHAR base;
317 WCHAR parts[3];
318 } VowelComponents;
320 typedef struct tagConsonantComponents
322 WCHAR parts[3];
323 WCHAR output;
324 } ConsonantComponents;
326 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
328 /* the orders of joined_forms and contextual_features need to line up */
329 static const char* contextual_features[] =
331 "isol",
332 "fina",
333 "init",
334 "medi",
335 /* Syriac Alaph */
336 "med2",
337 "fin2",
338 "fin3"
341 static OPENTYPE_FEATURE_RECORD standard_features[] =
343 { MS_MAKE_TAG('l','i','g','a'), 1},
344 { MS_MAKE_TAG('c','l','i','g'), 1},
347 static OPENTYPE_FEATURE_RECORD arabic_features[] =
349 { MS_MAKE_TAG('r','l','i','g'), 1},
350 { MS_MAKE_TAG('c','a','l','t'), 1},
351 { MS_MAKE_TAG('l','i','g','a'), 1},
352 { MS_MAKE_TAG('d','l','i','g'), 1},
353 { MS_MAKE_TAG('c','s','w','h'), 1},
354 { MS_MAKE_TAG('m','s','e','t'), 1},
357 static const char* required_arabic_features[] =
359 "fina",
360 "init",
361 "medi",
362 "rlig",
363 NULL
366 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
368 { MS_MAKE_TAG('d','l','i','g'), 1},
371 static OPENTYPE_FEATURE_RECORD syriac_features[] =
373 { MS_MAKE_TAG('r','l','i','g'), 1},
374 { MS_MAKE_TAG('c','a','l','t'), 1},
375 { MS_MAKE_TAG('l','i','g','a'), 1},
376 { MS_MAKE_TAG('d','l','i','g'), 1},
379 static const char* required_syriac_features[] =
381 "fina",
382 "fin2",
383 "fin3",
384 "init",
385 "medi",
386 "med2",
387 "rlig",
388 NULL
391 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
393 /* Presentation forms */
394 { MS_MAKE_TAG('b','l','w','s'), 1},
395 { MS_MAKE_TAG('a','b','v','s'), 1},
396 { MS_MAKE_TAG('p','s','t','s'), 1},
399 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
401 { MS_MAKE_TAG('a','b','v','s'), 1},
402 { MS_MAKE_TAG('b','l','w','s'), 1},
405 static OPENTYPE_FEATURE_RECORD thai_features[] =
407 { MS_MAKE_TAG('c','c','m','p'), 1},
410 static const char* required_lao_features[] =
412 "ccmp",
413 NULL
416 static const char* required_devanagari_features[] =
418 "nukt",
419 "akhn",
420 "rphf",
421 "blwf",
422 "half",
423 "vatu",
424 "pres",
425 "abvs",
426 "blws",
427 "psts",
428 "haln",
429 NULL
432 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
434 { MS_MAKE_TAG('p','r','e','s'), 1},
435 { MS_MAKE_TAG('a','b','v','s'), 1},
436 { MS_MAKE_TAG('b','l','w','s'), 1},
437 { MS_MAKE_TAG('p','s','t','s'), 1},
438 { MS_MAKE_TAG('h','a','l','n'), 1},
439 { MS_MAKE_TAG('c','a','l','t'), 1},
442 static const char* required_bengali_features[] =
444 "nukt",
445 "akhn",
446 "rphf",
447 "blwf",
448 "half",
449 "vatu",
450 "pstf",
451 "init",
452 "abvs",
453 "blws",
454 "psts",
455 "haln",
456 NULL
459 static const char* required_gurmukhi_features[] =
461 "nukt",
462 "akhn",
463 "rphf",
464 "blwf",
465 "half",
466 "pstf",
467 "vatu",
468 "cjct",
469 "pres",
470 "abvs",
471 "blws",
472 "psts",
473 "haln",
474 "calt",
475 NULL
478 static const char* required_oriya_features[] =
480 "nukt",
481 "akhn",
482 "rphf",
483 "blwf",
484 "pstf",
485 "cjct",
486 "pres",
487 "abvs",
488 "blws",
489 "psts",
490 "haln",
491 "calt",
492 NULL
495 static const char* required_tamil_features[] =
497 "nukt",
498 "akhn",
499 "rphf",
500 "pref",
501 "half",
502 "pres",
503 "abvs",
504 "blws",
505 "psts",
506 "haln",
507 "calt",
508 NULL
511 static const char* required_telugu_features[] =
513 "nukt",
514 "akhn",
515 "rphf",
516 "pref",
517 "half",
518 "pstf",
519 "cjct",
520 "pres",
521 "abvs",
522 "blws",
523 "psts",
524 "haln",
525 "calt",
526 NULL
529 typedef struct ScriptShapeDataTag {
530 TEXTRANGE_PROPERTIES defaultTextRange;
531 const char** requiredFeatures;
532 CHAR otTag[5];
533 CHAR newOtTag[5];
534 ContextualShapingProc contextProc;
535 ShapeCharGlyphPropProc charGlyphPropProc;
536 } ScriptShapeData;
538 /* in order of scripts */
539 static const ScriptShapeData ShapingData[] =
541 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
542 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
543 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
544 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
545 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
546 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
547 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
548 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
549 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
550 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
551 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
552 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
553 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
554 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
555 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
556 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
557 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
558 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
559 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
560 {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
561 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
562 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
563 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
564 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
565 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
566 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
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_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
570 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
571 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
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_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
575 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
576 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
577 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
578 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
579 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
580 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
581 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
582 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
583 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
584 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
585 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
586 {{ standard_features, 2}, NULL, "latn" , "", NULL, NULL},
589 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
591 const GSUB_CoverageFormat1* cf1;
593 cf1 = table;
595 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
597 int count = GET_BE_WORD(cf1->GlyphCount);
598 int i;
599 TRACE("Coverage Format 1, %i glyphs\n",count);
600 for (i = 0; i < count; i++)
601 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
602 return i;
603 return -1;
605 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
607 const GSUB_CoverageFormat2* cf2;
608 int i;
609 int count;
610 cf2 = (const GSUB_CoverageFormat2*)cf1;
612 count = GET_BE_WORD(cf2->RangeCount);
613 TRACE("Coverage Format 2, %i ranges\n",count);
614 for (i = 0; i < count; i++)
616 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
617 return -1;
618 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
619 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
621 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
622 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
625 return -1;
627 else
628 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
630 return -1;
633 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
635 const GSUB_ScriptList *script;
636 const GSUB_Script *deflt = NULL;
637 int i;
638 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
640 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
641 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
643 const GSUB_Script *scr;
644 int offset;
646 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
647 scr = (const GSUB_Script*)((const BYTE*)script + offset);
649 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
650 return scr;
651 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
652 deflt = scr;
654 return deflt;
657 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
659 int i;
660 int offset;
661 const GSUB_LangSys *Lang;
663 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
665 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
667 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
668 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
670 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
671 return Lang;
673 offset = GET_BE_WORD(script->DefaultLangSys);
674 if (offset)
676 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
677 return Lang;
679 return NULL;
682 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
684 int i;
685 const GSUB_FeatureList *feature;
686 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
688 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
689 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
691 int index = GET_BE_WORD(lang->FeatureIndex[i]);
692 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
694 const GSUB_Feature *feat;
695 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
696 return feat;
699 return NULL;
702 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
704 int j;
705 TRACE("Single Substitution Subtable\n");
707 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
709 int offset;
710 const GSUB_SingleSubstFormat1 *ssf1;
711 offset = GET_BE_WORD(look->SubTable[j]);
712 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
713 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
715 int offset = GET_BE_WORD(ssf1->Coverage);
716 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
717 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
719 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
720 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
721 TRACE(" 0x%x\n",glyphs[glyph_index]);
722 return glyph_index + 1;
725 else
727 const GSUB_SingleSubstFormat2 *ssf2;
728 INT index;
729 INT offset;
731 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
732 offset = GET_BE_WORD(ssf1->Coverage);
733 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
734 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
735 TRACE(" Coverage index %i\n",index);
736 if (index != -1)
738 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
739 return GSUB_E_NOGLYPH;
741 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
742 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
743 TRACE("0x%x\n",glyphs[glyph_index]);
744 return glyph_index + 1;
748 return GSUB_E_NOGLYPH;
751 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
753 int j;
754 TRACE("Multiple Substitution Subtable\n");
756 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
758 int offset, index;
759 const GSUB_MultipleSubstFormat1 *msf1;
760 offset = GET_BE_WORD(look->SubTable[j]);
761 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
763 offset = GET_BE_WORD(msf1->Coverage);
764 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
765 if (index != -1)
767 const GSUB_Sequence *seq;
768 int sub_count;
769 int j;
770 offset = GET_BE_WORD(msf1->Sequence[index]);
771 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
772 sub_count = GET_BE_WORD(seq->GlyphCount);
773 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
775 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
776 glyphs[j] =glyphs[j-(sub_count-1)];
778 for (j = 0; j < sub_count; j++)
779 if (write_dir < 0)
780 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
781 else
782 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
784 *glyph_count = *glyph_count + (sub_count - 1);
786 if (TRACE_ON(uniscribe))
788 for (j = 0; j < sub_count; j++)
789 TRACE(" 0x%x",glyphs[glyph_index+j]);
790 TRACE("\n");
793 return glyph_index + sub_count;
796 return GSUB_E_NOGLYPH;
799 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
801 int j;
802 TRACE("Alternate Substitution Subtable\n");
804 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
806 int offset;
807 const GSUB_AlternateSubstFormat1 *asf1;
808 INT index;
810 offset = GET_BE_WORD(look->SubTable[j]);
811 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
812 offset = GET_BE_WORD(asf1->Coverage);
814 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
815 if (index != -1)
817 const GSUB_AlternateSet *as;
818 offset = GET_BE_WORD(asf1->AlternateSet[index]);
819 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
820 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
821 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
822 return GSUB_E_NOGLYPH;
824 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
825 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
826 TRACE(" 0x%x\n",glyphs[glyph_index]);
827 return glyph_index + 1;
830 return GSUB_E_NOGLYPH;
833 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
835 int j;
837 TRACE("Ligature Substitution Subtable\n");
838 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
840 const GSUB_LigatureSubstFormat1 *lsf1;
841 int offset,index;
843 offset = GET_BE_WORD(look->SubTable[j]);
844 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
845 offset = GET_BE_WORD(lsf1->Coverage);
846 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
847 TRACE(" Coverage index %i\n",index);
848 if (index != -1)
850 const GSUB_LigatureSet *ls;
851 int k, count;
853 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
854 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
855 count = GET_BE_WORD(ls->LigatureCount);
856 TRACE(" LigatureSet has %i members\n",count);
857 for (k = 0; k < count; k++)
859 const GSUB_Ligature *lig;
860 int CompCount,l,CompIndex;
862 offset = GET_BE_WORD(ls->Ligature[k]);
863 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
864 CompCount = GET_BE_WORD(lig->CompCount) - 1;
865 CompIndex = glyph_index+write_dir;
866 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
868 int CompGlyph;
869 CompGlyph = GET_BE_WORD(lig->Component[l]);
870 if (CompGlyph != glyphs[CompIndex])
871 break;
872 CompIndex += write_dir;
874 if (l == CompCount)
876 int replaceIdx = glyph_index;
877 if (write_dir < 0)
878 replaceIdx = glyph_index - CompCount;
880 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
881 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
882 TRACE("0x%x\n",glyphs[replaceIdx]);
883 if (CompCount > 0)
885 int j;
886 for (j = replaceIdx + 1; j < *glyph_count; j++)
887 glyphs[j] =glyphs[j+CompCount];
888 *glyph_count = *glyph_count - CompCount;
890 return replaceIdx + 1;
895 return GSUB_E_NOGLYPH;
898 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
900 int j;
901 BOOL done = FALSE;
903 TRACE("Chaining Contextual Substitution Subtable\n");
904 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
906 const GSUB_ChainContextSubstFormat1 *ccsf1;
907 int offset;
908 int dirLookahead = write_dir;
909 int dirBacktrack = -1 * write_dir;
911 offset = GET_BE_WORD(look->SubTable[j]);
912 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
913 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
915 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
916 continue;
918 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
920 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
921 continue;
923 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
925 int k;
926 int indexGlyphs;
927 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
928 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
929 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
930 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
931 int newIndex = glyph_index;
933 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
935 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
937 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
939 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
940 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
941 break;
943 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
944 continue;
945 TRACE("Matched Backtrack\n");
947 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
949 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
950 for (k = 0; k < indexGlyphs; k++)
952 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
953 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
954 break;
956 if (k != indexGlyphs)
957 continue;
958 TRACE("Matched IndexGlyphs\n");
960 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
962 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
964 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
965 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
966 break;
968 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
969 continue;
970 TRACE("Matched LookAhead\n");
972 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
974 if (GET_BE_WORD(ccsf3_4->SubstCount))
976 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
978 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
979 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
981 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
982 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
983 if (newIndex == -1)
985 ERR("Chain failed to generate a glyph\n");
986 continue;
989 return newIndex;
991 else return GSUB_E_NOGLYPH;
994 return -1;
997 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
999 int offset;
1000 const GSUB_LookupTable *look;
1002 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1003 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1004 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1005 switch(GET_BE_WORD(look->LookupType))
1007 case 1:
1008 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1009 case 2:
1010 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1011 case 3:
1012 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1013 case 4:
1014 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1015 case 6:
1016 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1017 default:
1018 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1020 return GSUB_E_NOGLYPH;
1023 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1025 int i;
1026 int out_index = GSUB_E_NOGLYPH;
1027 const GSUB_LookupList *lookup;
1029 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1031 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1032 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1034 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1035 if (out_index != GSUB_E_NOGLYPH)
1036 break;
1038 if (out_index == GSUB_E_NOGLYPH)
1039 TRACE("lookups found no glyphs\n");
1040 else
1042 int out2;
1043 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1044 if (out2!=GSUB_E_NOGLYPH)
1045 out_index = out2;
1047 return out_index;
1050 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1052 UINT charset;
1054 if (psc->userScript != 0)
1056 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1057 return ShapingData[psa->eScript].newOtTag;
1058 else
1059 return (char*)&psc->userScript;
1062 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1063 return ShapingData[psa->eScript].newOtTag;
1065 if (ShapingData[psa->eScript].otTag[0] != 0)
1066 return ShapingData[psa->eScript].otTag;
1069 * fall back to the font charset
1071 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1072 switch (charset)
1074 case ANSI_CHARSET: return "latn";
1075 case BALTIC_CHARSET: return "latn"; /* ?? */
1076 case CHINESEBIG5_CHARSET: return "hani";
1077 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1078 case GB2312_CHARSET: return "hani";
1079 case GREEK_CHARSET: return "grek";
1080 case HANGUL_CHARSET: return "hang";
1081 case RUSSIAN_CHARSET: return "cyrl";
1082 case SHIFTJIS_CHARSET: return "kana";
1083 case TURKISH_CHARSET: return "latn"; /* ?? */
1084 case VIETNAMESE_CHARSET: return "latn";
1085 case JOHAB_CHARSET: return "latn"; /* ?? */
1086 case ARABIC_CHARSET: return "arab";
1087 case HEBREW_CHARSET: return "hebr";
1088 case THAI_CHARSET: return "thai";
1089 default: return "latn";
1093 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1095 const GSUB_Feature *feature;
1096 int i;
1098 for (i = 0; i < psc->feature_count; i++)
1099 if (strncmp(psc->features[i].tag,feat,4)==0)
1100 return psc->features[i].feature;
1102 feature = NULL;
1104 if (psc->GSUB_Table)
1106 const GSUB_Script *script;
1107 const GSUB_LangSys *language;
1108 int attempt = 2;
1112 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1113 attempt--;
1114 if (script)
1116 if (psc->userLang != 0)
1117 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1118 else
1119 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1120 if (language)
1121 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1123 } while(attempt && !feature);
1125 /* try in the default (latin) table */
1126 if (!feature)
1128 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1129 if (script)
1131 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1132 if (language)
1133 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1138 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1140 psc->feature_count++;
1142 if (psc->features)
1143 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1144 else
1145 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1147 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1148 psc->features[psc->feature_count - 1].feature = feature;
1149 return feature;
1152 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)
1154 const GSUB_Feature *feature;
1156 feature = load_GSUB_feature(hdc, psa, psc, feat);
1157 if (!feature)
1158 return GSUB_E_NOFEATURE;
1160 TRACE("applying feature %s\n",feat);
1161 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1164 static VOID *load_gsub_table(HDC hdc)
1166 VOID* GSUB_Table = NULL;
1167 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1168 if (length != GDI_ERROR)
1170 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1171 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1172 TRACE("Loaded GSUB table of %i bytes\n",length);
1174 return GSUB_Table;
1177 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)
1179 WORD *glyphs;
1180 INT glyph_count = count;
1181 INT rc;
1183 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1184 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1185 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1186 if (rc > GSUB_E_NOGLYPH)
1187 rc = count - glyph_count;
1188 else
1189 rc = 0;
1191 HeapFree(GetProcessHeap(),0,glyphs);
1192 return rc;
1195 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1197 int offset;
1198 WORD class = 0;
1199 const GDEF_ClassDefFormat1 *cf1;
1201 if (!header)
1202 return 0;
1204 offset = GET_BE_WORD(header->GlyphClassDef);
1205 if (!offset)
1206 return 0;
1208 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1209 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1211 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1213 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1214 if (index < GET_BE_WORD(cf1->GlyphCount))
1215 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1218 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1220 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1221 int i, top;
1222 top = GET_BE_WORD(cf2->ClassRangeCount);
1223 for (i = 0; i < top; i++)
1225 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1226 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1228 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1229 break;
1233 else
1234 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1236 return class;
1239 static VOID *load_gdef_table(HDC hdc)
1241 VOID* GDEF_Table = NULL;
1242 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1243 if (length != GDI_ERROR)
1245 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1246 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1247 TRACE("Loaded GDEF table of %i bytes\n",length);
1249 return GDEF_Table;
1252 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1254 int i;
1256 if (!psc->GDEF_Table)
1257 psc->GDEF_Table = load_gdef_table(hdc);
1259 for (i = 0; i < cGlyphs; i++)
1261 WORD class;
1263 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1265 switch (class)
1267 case 0:
1268 case BaseGlyph:
1269 pGlyphProp[i].sva.fClusterStart = 1;
1270 pGlyphProp[i].sva.fDiacritic = 0;
1271 pGlyphProp[i].sva.fZeroWidth = 0;
1272 break;
1273 case LigatureGlyph:
1274 pGlyphProp[i].sva.fClusterStart = 1;
1275 pGlyphProp[i].sva.fDiacritic = 0;
1276 pGlyphProp[i].sva.fZeroWidth = 0;
1277 break;
1278 case MarkGlyph:
1279 pGlyphProp[i].sva.fClusterStart = 0;
1280 pGlyphProp[i].sva.fDiacritic = 1;
1281 pGlyphProp[i].sva.fZeroWidth = 1;
1282 break;
1283 case ComponentGlyph:
1284 pGlyphProp[i].sva.fClusterStart = 0;
1285 pGlyphProp[i].sva.fDiacritic = 0;
1286 pGlyphProp[i].sva.fZeroWidth = 0;
1287 break;
1288 default:
1289 ERR("Unknown glyph class %i\n",class);
1290 pGlyphProp[i].sva.fClusterStart = 1;
1291 pGlyphProp[i].sva.fDiacritic = 0;
1292 pGlyphProp[i].sva.fZeroWidth = 0;
1297 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1299 int i;
1301 for (i = 0; i < cGlyphs; i++)
1303 if (!pGlyphProp[i].sva.fClusterStart)
1305 int j;
1306 for (j = 0; j < cChars; j++)
1308 if (pwLogClust[j] == i)
1310 int k = j;
1311 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1312 k-=1;
1313 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1314 pwLogClust[j] = pwLogClust[k];
1321 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1323 if (changeCount == 0)
1324 return;
1325 else
1327 int i;
1328 int target_glyph = nextIndex - 1;
1329 int seeking_glyph;
1330 int target_index = -1;
1331 int replacing_glyph = -1;
1332 int changed = 0;
1335 if (changeCount > 0)
1336 target_glyph = nextIndex - (changeCount+1);
1338 seeking_glyph = target_glyph;
1340 do {
1341 if (write_dir > 0)
1342 for (i = 0; i < chars; i++)
1344 if (pwLogClust[i] == seeking_glyph)
1346 target_index = i;
1347 break;
1350 else
1351 for (i = chars - 1; i >= 0; i--)
1353 if (pwLogClust[i] == seeking_glyph)
1355 target_index = i;
1356 break;
1359 if (target_index == -1)
1360 seeking_glyph ++;
1362 while (target_index == -1 && seeking_glyph < chars);
1364 if (target_index == -1)
1366 ERR("Unable to find target glyph\n");
1367 return;
1370 if (changeCount < 0)
1372 /* merge glyphs */
1373 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1375 if (pwLogClust[i] == target_glyph)
1376 continue;
1377 if(pwLogClust[i] == replacing_glyph)
1378 pwLogClust[i] = target_glyph;
1379 else
1381 changed--;
1382 if (changed >= changeCount)
1384 replacing_glyph = pwLogClust[i];
1385 pwLogClust[i] = target_glyph;
1387 else
1388 break;
1392 /* renumber trailing indexes*/
1393 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1395 if (pwLogClust[i] != target_glyph)
1396 pwLogClust[i] += changeCount;
1399 else
1401 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1402 pwLogClust[i] += changeCount;
1407 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 )
1409 int i;
1411 if (psc->GSUB_Table)
1413 const GSUB_Feature *feature;
1415 feature = load_GSUB_feature(hdc, psa, psc, feat);
1416 if (!feature)
1417 return GSUB_E_NOFEATURE;
1419 i = 0;
1420 TRACE("applying feature %s\n",debugstr_an(feat,4));
1421 while(i < *pcGlyphs)
1423 INT nextIndex;
1424 INT prevCount = *pcGlyphs;
1425 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1426 if (nextIndex > GSUB_E_NOGLYPH)
1428 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1429 i = nextIndex;
1431 else
1432 i++;
1434 return *pcGlyphs;
1436 return GSUB_E_NOFEATURE;
1439 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1441 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1444 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1446 if (i + delta < 0)
1447 return 0;
1448 if ( i+ delta >= cchLen)
1449 return 0;
1451 i += delta;
1453 return chars[i];
1456 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1458 if (i + delta < 0)
1460 if (psa->fLinkBefore)
1461 return jtR;
1462 else
1463 return jtU;
1465 if ( i+ delta >= cchLen)
1467 if (psa->fLinkAfter)
1468 return jtL;
1469 else
1470 return jtU;
1473 i += delta;
1475 if (context_type[i] == jtT)
1476 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1477 else
1478 return context_type[i];
1481 static inline BOOL right_join_causing(CHAR joining_type)
1483 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1486 static inline BOOL left_join_causing(CHAR joining_type)
1488 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1491 static inline BOOL word_break_causing(WCHAR chr)
1493 /* we are working within a string of characters already guareented to
1494 be within one script, Syriac, so we do not worry about any character
1495 other than the space character outside of that range */
1496 return (chr == 0 || chr == 0x20 );
1500 * ContextualShape_Arabic
1502 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1504 CHAR *context_type;
1505 INT *context_shape;
1506 INT dirR, dirL;
1507 int i;
1509 if (*pcGlyphs != cChars)
1511 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1512 return;
1515 if (!psa->fLogicalOrder && psa->fRTL)
1517 dirR = 1;
1518 dirL = -1;
1520 else
1522 dirR = -1;
1523 dirL = 1;
1526 if (!psc->GSUB_Table)
1527 psc->GSUB_Table = load_gsub_table(hdc);
1529 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1530 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1532 for (i = 0; i < cChars; i++)
1533 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1535 for (i = 0; i < cChars; i++)
1537 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1538 context_shape[i] = Xr;
1539 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1540 context_shape[i] = Xl;
1541 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)))
1542 context_shape[i] = Xm;
1543 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1544 context_shape[i] = Xr;
1545 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1546 context_shape[i] = Xl;
1547 else
1548 context_shape[i] = Xn;
1551 /* Contextual Shaping */
1552 i = 0;
1553 while(i < *pcGlyphs)
1555 BOOL shaped = FALSE;
1557 if (psc->GSUB_Table)
1559 INT nextIndex;
1560 INT prevCount = *pcGlyphs;
1561 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1562 if (nextIndex > GSUB_E_NOGLYPH)
1564 i = nextIndex;
1565 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1567 shaped = (nextIndex > GSUB_E_NOGLYPH);
1570 if (!shaped)
1572 if (context_shape[i] == Xn)
1574 WORD newGlyph = pwOutGlyphs[i];
1575 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1577 /* fall back to presentation form B */
1578 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1579 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1580 pwOutGlyphs[i] = newGlyph;
1583 i++;
1587 HeapFree(GetProcessHeap(),0,context_shape);
1588 HeapFree(GetProcessHeap(),0,context_type);
1592 * ContextualShape_Syriac
1595 #define ALAPH 0x710
1596 #define DALATH 0x715
1597 #define RISH 0x72A
1599 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1601 CHAR *context_type;
1602 INT *context_shape;
1603 INT dirR, dirL;
1604 int i;
1606 if (*pcGlyphs != cChars)
1608 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1609 return;
1612 if (!psa->fLogicalOrder && psa->fRTL)
1614 dirR = 1;
1615 dirL = -1;
1617 else
1619 dirR = -1;
1620 dirL = 1;
1623 if (!psc->GSUB_Table)
1624 psc->GSUB_Table = load_gsub_table(hdc);
1626 if (!psc->GSUB_Table)
1627 return;
1629 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1630 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1632 for (i = 0; i < cChars; i++)
1633 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1635 for (i = 0; i < cChars; i++)
1637 if (pwcChars[i] == ALAPH)
1639 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1641 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1642 context_shape[i] = Afj;
1643 else if ( rchar != DALATH && rchar != RISH &&
1644 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1645 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1646 context_shape[i] = Afn;
1647 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1648 context_shape[i] = Afx;
1649 else
1650 context_shape[i] = Xn;
1652 else if (context_type[i] == jtR &&
1653 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1654 context_shape[i] = Xr;
1655 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1656 context_shape[i] = Xl;
1657 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)))
1658 context_shape[i] = Xm;
1659 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1660 context_shape[i] = Xr;
1661 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1662 context_shape[i] = Xl;
1663 else
1664 context_shape[i] = Xn;
1667 /* Contextual Shaping */
1668 i = 0;
1669 while(i < *pcGlyphs)
1671 INT nextIndex;
1672 INT prevCount = *pcGlyphs;
1673 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1674 if (nextIndex > GSUB_E_NOGLYPH)
1676 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1677 i = nextIndex;
1679 else
1680 i++;
1683 HeapFree(GetProcessHeap(),0,context_shape);
1684 HeapFree(GetProcessHeap(),0,context_type);
1688 * ContextualShape_Phags_pa
1691 #define phags_pa_CANDRABINDU 0xA873
1692 #define phags_pa_START 0xA840
1693 #define phags_pa_END 0xA87F
1695 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1697 INT *context_shape;
1698 INT dirR, dirL;
1699 int i;
1701 if (*pcGlyphs != cChars)
1703 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1704 return;
1707 if (!psa->fLogicalOrder && psa->fRTL)
1709 dirR = 1;
1710 dirL = -1;
1712 else
1714 dirR = -1;
1715 dirL = 1;
1718 if (!psc->GSUB_Table)
1719 psc->GSUB_Table = load_gsub_table(hdc);
1721 if (!psc->GSUB_Table)
1722 return;
1724 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1726 for (i = 0; i < cChars; i++)
1728 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1730 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1731 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1732 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1733 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1735 if (jrchar && jlchar)
1736 context_shape[i] = Xm;
1737 else if (jrchar)
1738 context_shape[i] = Xr;
1739 else if (jlchar)
1740 context_shape[i] = Xl;
1741 else
1742 context_shape[i] = Xn;
1744 else
1745 context_shape[i] = -1;
1748 /* Contextual Shaping */
1749 i = 0;
1750 while(i < *pcGlyphs)
1752 if (context_shape[i] >= 0)
1754 INT nextIndex;
1755 INT prevCount = *pcGlyphs;
1756 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1757 if (nextIndex > GSUB_E_NOGLYPH)
1759 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1760 i = nextIndex;
1762 else
1763 i++;
1765 else
1766 i++;
1769 HeapFree(GetProcessHeap(),0,context_shape);
1772 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1774 int i;
1776 /* Replace */
1777 pwOutChars[cWalk] = replacements[0];
1778 cWalk=cWalk+1;
1780 /* Insert */
1781 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1783 int j;
1784 for (j = *pcChars; j > cWalk; j--)
1785 pwOutChars[j] = pwOutChars[j-1];
1786 *pcChars= *pcChars+1;
1787 pwOutChars[cWalk] = replacements[i];
1788 cWalk = cWalk+1;
1792 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust)
1794 int i;
1795 int cWalk;
1796 int offset = 0;
1798 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1800 for (i = 0; vowels[i].base != 0x0; i++)
1802 if (pwOutChars[cWalk] == vowels[i].base)
1804 int j;
1805 int o = 1;
1806 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1807 if (vowels[i].parts[1]) { cWalk++; o++; }
1808 if (vowels[i].parts[2]) { cWalk++; o++; }
1809 offset += o;
1810 for (j = (cWalk - offset) + 1; j < *pcChars - offset; j ++)
1811 pwLogClust[j]+=o;
1812 break;
1818 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1820 int i;
1821 int offset = 0;
1822 int cWalk;
1824 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1826 for (i = 0; consonants[i].output!= 0x0; i++)
1828 int j;
1829 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1830 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1831 break;
1833 if (consonants[i].parts[j]==0x0) /* matched all */
1835 int k;
1836 j--;
1837 pwOutChars[cWalk] = consonants[i].output;
1838 for(k = cWalk+1; k < *pcChars - j; k++)
1839 pwOutChars[k] = pwOutChars[k+j];
1840 *pcChars = *pcChars - j;
1841 for (k = j ; k > 0; k--)
1842 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1843 offset += j;
1844 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1845 pwLogClust[k]--;
1846 break;
1849 cWalk++;
1853 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1855 if (s->ralf >= 0)
1857 int j;
1858 WORD Ra = pwChar[s->start];
1859 WORD H = pwChar[s->start+1];
1861 TRACE("Doing reorder of Ra to %i\n",s->base);
1862 for (j = s->start; j < s->base-1; j++)
1863 pwChar[j] = pwChar[j+2];
1864 pwChar[s->base-1] = Ra;
1865 pwChar[s->base] = H;
1867 s->ralf = s->base-1;
1868 s->base -= 2;
1872 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1874 if (s->ralf >= 0)
1876 int j,loc;
1877 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1878 WORD Ra = pwChar[s->start];
1879 WORD H = pwChar[s->start+1];
1880 for (loc = s->end; loc > stop; loc--)
1881 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1882 break;
1884 TRACE("Doing reorder of Ra to %i\n",loc);
1885 for (j = s->start; j < loc-1; j++)
1886 pwChar[j] = pwChar[j+2];
1887 pwChar[loc-1] = Ra;
1888 pwChar[loc] = H;
1890 s->ralf = loc-1;
1891 s->base -= 2;
1892 if (s->blwf >= 0) s->blwf -= 2;
1893 if (s->pref >= 0) s->pref -= 2;
1897 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1899 if (s->ralf >= 0)
1901 int j;
1902 WORD Ra = pwChar[s->start];
1903 WORD H = pwChar[s->start+1];
1905 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1906 for (j = s->start; j < s->end-1; j++)
1907 pwChar[j] = pwChar[j+2];
1908 pwChar[s->end-1] = Ra;
1909 pwChar[s->end] = H;
1911 s->ralf = s->end-1;
1912 s->base -= 2;
1913 if (s->blwf >= 0) s->blwf -= 2;
1914 if (s->pref >= 0) s->pref -= 2;
1918 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1920 int i;
1922 /* reorder Matras */
1923 if (s->end > s->base)
1925 for (i = 1; i <= s->end-s->base; i++)
1927 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1929 int j;
1930 WCHAR c = pwChar[s->base+i];
1931 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1932 for (j = s->base+i; j > s->base; j--)
1933 pwChar[j] = pwChar[j-1];
1934 pwChar[s->base] = c;
1936 if (s->ralf >= s->base) s->ralf++;
1937 if (s->blwf >= s->base) s->blwf++;
1938 if (s->pref >= s->base) s->pref++;
1939 s->base ++;
1945 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1947 int i;
1949 /* reorder Matras */
1950 if (s->end > s->base)
1952 for (i = 1; i <= s->end-s->base; i++)
1954 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1956 int j;
1957 WCHAR c = pwChar[s->base+i];
1958 TRACE("Doing reorder of %x to %i\n",c,s->start);
1959 for (j = s->base+i; j > s->start; j--)
1960 pwChar[j] = pwChar[j-1];
1961 pwChar[s->start] = c;
1963 if (s->ralf >= 0) s->ralf++;
1964 if (s->blwf >= 0) s->blwf++;
1965 if (s->pref >= 0) s->pref++;
1966 s->base ++;
1972 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1974 if (s->blwf >= 0 && g->blwf > g->base)
1976 int j,loc;
1977 int g_offset;
1978 for (loc = s->end; loc > s->blwf; loc--)
1979 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1980 break;
1982 g_offset = (loc - s->blwf) - 1;
1984 if (loc != s->blwf)
1986 WORD blwf = glyphs[g->blwf];
1987 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1988 /* do not care about the pwChar array anymore, just the glyphs */
1989 for (j = 0; j < g_offset; j++)
1990 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1991 glyphs[g->blwf + g_offset] = blwf;
1996 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1998 int i;
2000 /* reorder previously moved Matras to correct position*/
2001 for (i = s->start; i < s->base; i++)
2003 if (lexical(pwChar[i]) == lex_Matra_pre)
2005 int j;
2006 int g_start = g->start + i - s->start;
2007 if (g_start < g->base -1 )
2009 WCHAR og = glyphs[g_start];
2010 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2011 for (j = g_start; j < g->base-1; j++)
2012 glyphs[j] = glyphs[j+1];
2013 glyphs[g->base-1] = og;
2019 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2021 if (s->pref >= 0 && g->pref > g->base)
2023 int j;
2024 WCHAR og = glyphs[g->pref];
2025 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2026 for (j = g->pref; j > g->base; j--)
2027 glyphs[j] = glyphs[j-1];
2028 glyphs[g->base] = og;
2032 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2034 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2035 if (s->start == s->base && s->base == s->end) return;
2036 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2038 Reorder_Ra_follows_base(pwChar, s, lexical);
2039 Reorder_Matra_precede_base(pwChar, s, lexical);
2042 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2044 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2045 if (s->start == s->base && s->base == s->end) return;
2046 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2048 Reorder_Ra_follows_matra(pwChar, s, lexical);
2049 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2052 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2054 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2055 if (s->start == s->base && s->base == s->end) return;
2056 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2058 Reorder_Ra_follows_base(pwChar, s, lexical);
2059 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2062 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2064 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2065 if (s->start == s->base && s->base == s->end) return;
2066 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2068 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2069 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2072 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2074 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2075 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2076 if (s->start == s->base && s->base == s->end) return;
2077 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2079 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2082 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2084 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2085 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2086 if (s->start == s->base && s->base == s->end) return;
2087 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2089 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2090 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2094 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2096 if (shift == 0)
2097 return;
2099 if (glyph_index->start > index)
2100 glyph_index->start += shift;
2101 if (glyph_index->base > index)
2102 glyph_index->base+= shift;
2103 if (glyph_index->end > index)
2104 glyph_index->end+= shift;
2105 if (glyph_index->ralf > index)
2106 glyph_index->ralf+= shift;
2107 if (glyph_index->blwf > index)
2108 glyph_index->blwf+= shift;
2109 if (glyph_index->pref > index)
2110 glyph_index->pref+= shift;
2113 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 )
2115 int index = glyph_index->start;
2117 if (!feature)
2118 return;
2120 while(index <= glyph_index->end)
2122 INT nextIndex;
2123 INT prevCount = *pcGlyphs;
2124 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2125 if (nextIndex > GSUB_E_NOGLYPH)
2127 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2128 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2129 index = nextIndex;
2131 else
2132 index++;
2136 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2138 int i = 0;
2139 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)))))
2140 i++;
2141 if (index + i <= end-1)
2142 return index + i;
2143 else
2144 return -1;
2147 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)
2149 INT index, nextIndex;
2150 INT count,g_offset;
2152 count = syllable->base - syllable->start;
2154 g_offset = 0;
2155 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2156 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2158 INT prevCount = *pcGlyphs;
2159 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2160 if (nextIndex > GSUB_E_NOGLYPH)
2162 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2163 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2164 g_offset += (*pcGlyphs - prevCount);
2167 index+=2;
2168 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2172 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)
2174 INT nextIndex;
2175 INT prevCount = *pcGlyphs;
2177 if (syllable->ralf >= 0)
2179 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2180 if (nextIndex > GSUB_E_NOGLYPH)
2182 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2183 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2188 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2190 int i = 0;
2191 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2192 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2193 is_consonant(lexical(pwChars[index+i+1])))))
2194 i++;
2195 if (index + i <= end-1)
2196 return index+i;
2197 else
2198 return -1;
2201 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)
2203 INT index, nextIndex;
2204 INT count, g_offset=0;
2205 INT ralf = syllable->ralf;
2207 count = syllable->end - syllable->base;
2209 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2211 while (index >= 0)
2213 INT prevCount = *pcGlyphs;
2214 if (ralf >=0 && ralf < index)
2216 g_offset--;
2217 ralf = -1;
2220 if (!modern)
2222 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2223 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2224 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2227 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2228 if (nextIndex > GSUB_E_NOGLYPH)
2230 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2231 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2232 g_offset += (*pcGlyphs - prevCount);
2234 else if (!modern)
2236 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2237 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2238 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2241 index+=2;
2242 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2246 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)
2248 int c;
2249 int overall_shift = 0;
2250 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2251 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2252 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2253 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2254 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2255 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2256 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2257 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2258 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2259 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2260 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2261 IndicSyllable glyph_indexs;
2263 for (c = 0; c < syllable_count; c++)
2265 int old_end;
2266 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2267 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2268 old_end = glyph_indexs.end;
2270 if (locl)
2272 TRACE("applying feature locl\n");
2273 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2275 if (nukt)
2277 TRACE("applying feature nukt\n");
2278 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2280 if (akhn)
2282 TRACE("applying feature akhn\n");
2283 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2286 if (rphf)
2287 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2288 if (rkrf)
2290 TRACE("applying feature rkrf\n");
2291 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2293 if (pref)
2294 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2295 if (blwf)
2297 if (!modern)
2298 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2300 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2303 if (half)
2304 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2305 if (pstf)
2307 TRACE("applying feature pstf\n");
2308 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2310 if (vatu)
2312 TRACE("applying feature vatu\n");
2313 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2315 if (cjct)
2317 TRACE("applying feature cjct\n");
2318 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2321 if (second_reorder)
2322 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2324 overall_shift += glyph_indexs.end - old_end;
2328 static inline int unicode_lex(WCHAR c)
2330 int type;
2332 if (!c) return lex_Generic;
2333 if (c == 0x200D) return lex_ZWJ;
2334 if (c == 0x200C) return lex_ZWNJ;
2335 if (c == 0x00A0) return lex_NBSP;
2337 type = get_table_entry( indic_syllabic_table, c );
2339 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2341 switch( type )
2343 case 0x0d07: /* Unknown */
2344 case 0x0e07: /* Unknwon */
2345 default: return lex_Generic;
2346 case 0x0001:
2347 case 0x0002:
2348 case 0x0011:
2349 case 0x0012:
2350 case 0x0013:
2351 case 0x0014: return lex_Modifier;
2352 case 0x0003:
2353 case 0x0009:
2354 case 0x000a:
2355 case 0x000b:
2356 case 0x000d:
2357 case 0x000e:
2358 case 0x000f:
2359 case 0x0010: return lex_Consonant;
2360 case 0x0004: return lex_Nukta;
2361 case 0x0005: return lex_Halant;
2362 case 0x0006:
2363 case 0x0008: return lex_Vowel;
2364 case 0x0007:
2365 case 0x0107: return lex_Matra_post;
2366 case 0x0207:
2367 case 0x0307: return lex_Matra_pre;
2368 case 0x0807:
2369 case 0x0907:
2370 case 0x0a07:
2371 case 0x0b07:
2372 case 0x0c07:
2373 case 0x0407: return lex_Composed_Vowel;
2374 case 0x0507: return lex_Matra_above;
2375 case 0x0607: return lex_Matra_below;
2376 case 0x000c: return lex_Ra;
2380 static int sinhala_lex(WCHAR c)
2382 switch (c)
2384 case 0x0DDA:
2385 case 0x0DDD:
2386 case 0x0DDC:
2387 case 0x0DDE: return lex_Matra_post;
2388 default:
2389 return unicode_lex(c);
2393 static const VowelComponents Sinhala_vowels[] = {
2394 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2395 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2396 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2397 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2398 {0x0000, {0x0000,0x0000,0x0}}};
2400 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2402 int cCount = cChars;
2403 int i;
2404 WCHAR *input;
2405 IndicSyllable *syllables = NULL;
2406 int syllable_count = 0;
2408 if (*pcGlyphs != cChars)
2410 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2411 return;
2414 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2416 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2418 /* Step 1: Decompose multi part vowels */
2419 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust);
2421 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2423 /* Step 2: Reorder within Syllables */
2424 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2425 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2427 /* Step 3: Strip dangling joiners */
2428 for (i = 0; i < cCount; i++)
2430 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2431 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2432 input[i] = 0x0020;
2435 /* Step 4: Base Form application to syllables */
2436 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2437 *pcGlyphs = cCount;
2438 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2440 HeapFree(GetProcessHeap(),0,input);
2441 HeapFree(GetProcessHeap(),0,syllables);
2444 static int devanagari_lex(WCHAR c)
2446 switch (c)
2448 case 0x0930: return lex_Ra;
2449 default:
2450 return unicode_lex(c);
2454 static const ConsonantComponents Devanagari_consonants[] ={
2455 {{0x0928, 0x093C, 0x00000}, 0x0929},
2456 {{0x0930, 0x093C, 0x00000}, 0x0931},
2457 {{0x0933, 0x093C, 0x00000}, 0x0934},
2458 {{0x0915, 0x093C, 0x00000}, 0x0958},
2459 {{0x0916, 0x093C, 0x00000}, 0x0959},
2460 {{0x0917, 0x093C, 0x00000}, 0x095A},
2461 {{0x091C, 0x093C, 0x00000}, 0x095B},
2462 {{0x0921, 0x093C, 0x00000}, 0x095C},
2463 {{0x0922, 0x093C, 0x00000}, 0x095D},
2464 {{0x092B, 0x093C, 0x00000}, 0x095E},
2465 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2467 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2469 int cCount = cChars;
2470 WCHAR *input;
2471 IndicSyllable *syllables = NULL;
2472 int syllable_count = 0;
2473 BOOL modern = get_GSUB_Indic2(psa, psc);
2475 if (*pcGlyphs != cChars)
2477 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2478 return;
2481 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2482 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2484 /* Step 1: Compose Consonant and Nukta */
2485 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2486 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2488 /* Step 2: Reorder within Syllables */
2489 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2490 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2491 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2492 *pcGlyphs = cCount;
2494 /* Step 3: Base Form application to syllables */
2495 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2497 HeapFree(GetProcessHeap(),0,input);
2498 HeapFree(GetProcessHeap(),0,syllables);
2501 static int bengali_lex(WCHAR c)
2503 switch (c)
2505 case 0x09B0: return lex_Ra;
2506 default:
2507 return unicode_lex(c);
2511 static const VowelComponents Bengali_vowels[] = {
2512 {0x09CB, {0x09C7,0x09BE,0x0000}},
2513 {0x09CC, {0x09C7,0x09D7,0x0000}},
2514 {0x0000, {0x0000,0x0000,0x0000}}};
2516 static const ConsonantComponents Bengali_consonants[] = {
2517 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2518 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2519 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2520 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2521 {{0x0000,0x0000,0x0000}, 0x0000}};
2523 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2525 int cCount = cChars;
2526 WCHAR *input;
2527 IndicSyllable *syllables = NULL;
2528 int syllable_count = 0;
2529 BOOL modern = get_GSUB_Indic2(psa, psc);
2531 if (*pcGlyphs != cChars)
2533 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2534 return;
2537 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2538 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2540 /* Step 1: Decompose Vowels and Compose Consonents */
2541 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust);
2542 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2543 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2545 /* Step 2: Reorder within Syllables */
2546 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2547 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2548 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2549 *pcGlyphs = cCount;
2551 /* Step 3: Initial form is only applied to the beginning of words */
2552 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2554 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2556 int index = cCount;
2557 int gCount = 1;
2558 if (index > 0) index++;
2560 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2564 /* Step 4: Base Form application to syllables */
2565 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2567 HeapFree(GetProcessHeap(),0,input);
2568 HeapFree(GetProcessHeap(),0,syllables);
2571 static int gurmukhi_lex(WCHAR c)
2573 return unicode_lex(c);
2576 static const ConsonantComponents Gurmukhi_consonants[] = {
2577 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2578 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2579 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2580 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2581 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2582 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2583 {{0x0000,0x0000,0x0000}, 0x0000}};
2585 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2587 int cCount = cChars;
2588 WCHAR *input;
2589 IndicSyllable *syllables = NULL;
2590 int syllable_count = 0;
2591 BOOL modern = get_GSUB_Indic2(psa, psc);
2593 if (*pcGlyphs != cChars)
2595 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2596 return;
2599 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2600 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2602 /* Step 1: Compose Consonents */
2603 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2604 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2606 /* Step 2: Reorder within Syllables */
2607 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2608 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2609 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2610 *pcGlyphs = cCount;
2612 /* Step 3: Base Form application to syllables */
2613 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2615 HeapFree(GetProcessHeap(),0,input);
2616 HeapFree(GetProcessHeap(),0,syllables);
2619 static int gujarati_lex(WCHAR c)
2621 switch (c)
2623 case 0x0AB0: return lex_Ra;
2624 default:
2625 return unicode_lex(c);
2629 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2631 int cCount = cChars;
2632 WCHAR *input;
2633 IndicSyllable *syllables = NULL;
2634 int syllable_count = 0;
2635 BOOL modern = get_GSUB_Indic2(psa, psc);
2637 if (*pcGlyphs != cChars)
2639 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2640 return;
2643 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2644 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2646 /* Step 1: Reorder within Syllables */
2647 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2648 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2649 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2650 *pcGlyphs = cCount;
2652 /* Step 2: Base Form application to syllables */
2653 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2655 HeapFree(GetProcessHeap(),0,input);
2656 HeapFree(GetProcessHeap(),0,syllables);
2659 static int oriya_lex(WCHAR c)
2661 switch (c)
2663 case 0x0B30: return lex_Ra;
2664 default:
2665 return unicode_lex(c);
2669 static const VowelComponents Oriya_vowels[] = {
2670 {0x0B48, {0x0B47,0x0B56,0x0000}},
2671 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2672 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2673 {0x0000, {0x0000,0x0000,0x0000}}};
2675 static const ConsonantComponents Oriya_consonants[] = {
2676 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2677 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2678 {{0x0000,0x0000,0x0000}, 0x0000}};
2680 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2682 int cCount = cChars;
2683 WCHAR *input;
2684 IndicSyllable *syllables = NULL;
2685 int syllable_count = 0;
2686 BOOL modern = get_GSUB_Indic2(psa, psc);
2688 if (*pcGlyphs != cChars)
2690 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2691 return;
2694 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2695 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2697 /* Step 1: Decompose Vowels and Compose Consonents */
2698 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust);
2699 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2700 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2702 /* Step 2: Reorder within Syllables */
2703 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2704 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2705 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2706 *pcGlyphs = cCount;
2708 /* Step 3: Base Form application to syllables */
2709 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2711 HeapFree(GetProcessHeap(),0,input);
2712 HeapFree(GetProcessHeap(),0,syllables);
2715 static int tamil_lex(WCHAR c)
2717 return unicode_lex(c);
2720 static const VowelComponents Tamil_vowels[] = {
2721 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2722 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2723 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2724 {0x0000, {0x0000,0x0000,0x0000}}};
2726 static const ConsonantComponents Tamil_consonants[] = {
2727 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2728 {{0x0000,0x0000,0x0000}, 0x0000}};
2730 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2732 int cCount = cChars;
2733 WCHAR *input;
2734 IndicSyllable *syllables = NULL;
2735 int syllable_count = 0;
2736 BOOL modern = get_GSUB_Indic2(psa, psc);
2738 if (*pcGlyphs != cChars)
2740 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2741 return;
2744 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2745 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2747 /* Step 1: Decompose Vowels and Compose Consonents */
2748 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust);
2749 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2750 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2752 /* Step 2: Reorder within Syllables */
2753 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2754 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2755 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2756 *pcGlyphs = cCount;
2758 /* Step 3: Base Form application to syllables */
2759 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2761 HeapFree(GetProcessHeap(),0,input);
2762 HeapFree(GetProcessHeap(),0,syllables);
2765 static int telugu_lex(WCHAR c)
2767 switch (c)
2769 case 0x0C43:
2770 case 0x0C44: return lex_Modifier;
2771 default:
2772 return unicode_lex(c);
2776 static const VowelComponents Telugu_vowels[] = {
2777 {0x0C48, {0x0C46,0x0C56,0x0000}},
2778 {0x0000, {0x0000,0x0000,0x0000}}};
2780 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2782 int cCount = cChars;
2783 WCHAR *input;
2784 IndicSyllable *syllables = NULL;
2785 int syllable_count = 0;
2786 BOOL modern = get_GSUB_Indic2(psa, psc);
2788 if (*pcGlyphs != cChars)
2790 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2791 return;
2794 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2795 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2797 /* Step 1: Decompose Vowels */
2798 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust);
2799 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2801 /* Step 2: Reorder within Syllables */
2802 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2803 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2804 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2805 *pcGlyphs = cCount;
2807 /* Step 3: Base Form application to syllables */
2808 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2810 HeapFree(GetProcessHeap(),0,input);
2811 HeapFree(GetProcessHeap(),0,syllables);
2814 static int kannada_lex(WCHAR c)
2816 switch (c)
2818 case 0x0CB0: return lex_Ra;
2819 default:
2820 return unicode_lex(c);
2824 static const VowelComponents Kannada_vowels[] = {
2825 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2826 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2827 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2828 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2829 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2830 {0x0000, {0x0000,0x0000,0x0000}}};
2832 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2834 int cCount = cChars;
2835 WCHAR *input;
2836 IndicSyllable *syllables = NULL;
2837 int syllable_count = 0;
2838 BOOL modern = get_GSUB_Indic2(psa, psc);
2840 if (*pcGlyphs != cChars)
2842 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2843 return;
2846 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2847 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2849 /* Step 1: Decompose Vowels */
2850 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust);
2851 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2853 /* Step 2: Reorder within Syllables */
2854 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2855 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2856 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2857 *pcGlyphs = cCount;
2859 /* Step 3: Base Form application to syllables */
2860 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2862 HeapFree(GetProcessHeap(),0,input);
2863 HeapFree(GetProcessHeap(),0,syllables);
2866 static int malayalam_lex(WCHAR c)
2868 return unicode_lex(c);
2871 static const VowelComponents Malayalam_vowels[] = {
2872 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2873 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2874 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2875 {0x0000, {0x0000,0x0000,0x0000}}};
2877 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2879 int cCount = cChars;
2880 WCHAR *input;
2881 IndicSyllable *syllables = NULL;
2882 int syllable_count = 0;
2883 BOOL modern = get_GSUB_Indic2(psa, psc);
2885 if (*pcGlyphs != cChars)
2887 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2888 return;
2891 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2892 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2894 /* Step 1: Decompose Vowels */
2895 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust);
2896 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2898 /* Step 2: Reorder within Syllables */
2899 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2900 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2901 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2902 *pcGlyphs = cCount;
2904 /* Step 3: Base Form application to syllables */
2905 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2907 HeapFree(GetProcessHeap(),0,input);
2908 HeapFree(GetProcessHeap(),0,syllables);
2911 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)
2913 int i,k;
2915 for (i = 0; i < cGlyphs; i++)
2917 int char_index[20];
2918 int char_count = 0;
2920 for (k = 0; k < cChars; k++)
2922 if (pwLogClust[k] == i)
2924 char_index[char_count] = k;
2925 char_count++;
2929 if (char_count == 0)
2931 FIXME("No chars in this glyph? Must be an error\n");
2932 continue;
2935 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2937 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2938 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2940 else
2941 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2944 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2945 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2948 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 )
2950 int i,k;
2951 int initGlyph, finaGlyph;
2952 INT dirR, dirL;
2953 BYTE *spaces;
2955 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2956 memset(spaces,0,cGlyphs);
2958 if (!psa->fLogicalOrder && psa->fRTL)
2960 initGlyph = cGlyphs-1;
2961 finaGlyph = 0;
2962 dirR = 1;
2963 dirL = -1;
2965 else
2967 initGlyph = 0;
2968 finaGlyph = cGlyphs-1;
2969 dirR = -1;
2970 dirL = 1;
2973 for (i = 0; i < cGlyphs; i++)
2975 for (k = 0; k < cChars; k++)
2976 if (pwLogClust[k] == i)
2978 if (pwcChars[k] == 0x0020)
2979 spaces[i] = 1;
2983 for (i = 0; i < cGlyphs; i++)
2985 int char_index[20];
2986 int char_count = 0;
2987 BOOL isInit, isFinal;
2989 for (k = 0; k < cChars; k++)
2991 if (pwLogClust[k] == i)
2993 char_index[char_count] = k;
2994 char_count++;
2998 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2999 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3001 if (char_count == 0)
3003 FIXME("No chars in this glyph? Must be an error\n");
3004 continue;
3007 if (char_count == 1)
3009 if (pwcChars[char_index[0]] == 0x0020) /* space */
3011 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3012 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3014 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3015 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3016 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3018 if (!isInit && !isFinal)
3019 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3020 else if (isInit)
3021 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3022 else
3023 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3025 else if (!isInit)
3027 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3029 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3030 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3031 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3032 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3033 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3034 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3035 else
3036 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3038 else if (!isInit && !isFinal)
3039 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3040 else
3041 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3043 else if (char_count == 2)
3045 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3046 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3047 else if (!isInit)
3048 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3049 else
3050 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3052 else if (!isInit && !isFinal)
3053 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3054 else
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3058 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3059 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3060 HeapFree(GetProcessHeap(),0,spaces);
3063 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 )
3065 int i,k;
3066 int finaGlyph;
3067 INT dirL;
3068 BYTE *spaces;
3070 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3071 memset(spaces,0,cGlyphs);
3073 if (!psa->fLogicalOrder && psa->fRTL)
3075 finaGlyph = 0;
3076 dirL = -1;
3078 else
3080 finaGlyph = cGlyphs-1;
3081 dirL = 1;
3084 for (i = 0; i < cGlyphs; i++)
3086 for (k = 0; k < cChars; k++)
3087 if (pwLogClust[k] == i)
3089 if (pwcChars[k] == 0x0020)
3090 spaces[i] = 1;
3094 for (i = 0; i < cGlyphs; i++)
3096 int char_index[20];
3097 int char_count = 0;
3099 for (k = 0; k < cChars; k++)
3101 if (pwLogClust[k] == i)
3103 char_index[char_count] = k;
3104 char_count++;
3108 if (char_count == 0)
3110 FIXME("No chars in this glyph? Must be an error\n");
3111 continue;
3114 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3116 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3117 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3119 else if (i == finaGlyph)
3120 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3121 else
3122 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3125 HeapFree(GetProcessHeap(),0,spaces);
3126 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3127 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3129 /* Do not allow justification between marks and their base */
3130 for (i = 0; i < cGlyphs; i++)
3132 if (!pGlyphProp[i].sva.fClusterStart)
3133 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3137 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)
3139 int i,k;
3141 for (i = 0; i < cGlyphs; i++)
3143 int char_index[20];
3144 int char_count = 0;
3146 for (k = 0; k < cChars; k++)
3148 if (pwLogClust[k] == i)
3150 char_index[char_count] = k;
3151 char_count++;
3155 if (char_count == 0)
3157 FIXME("No chars in this glyph? Must be an error\n");
3158 continue;
3161 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3163 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3164 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3166 else
3167 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3169 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3170 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3173 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)
3175 int i,k;
3177 for (i = 0; i < cGlyphs; i++)
3179 int char_index[20];
3180 int char_count = 0;
3182 for (k = 0; k < cChars; k++)
3184 if (pwLogClust[k] == i)
3186 char_index[char_count] = k;
3187 char_count++;
3191 if (char_count == 0)
3193 FIXME("No chars in this glyph? Must be an error\n");
3194 continue;
3197 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3199 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3200 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3202 else
3203 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3205 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3206 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3208 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3209 for (i = 0; i < cGlyphs; i++)
3211 if (!pGlyphProp[i].sva.fClusterStart)
3213 pGlyphProp[i].sva.fDiacritic = 0;
3214 pGlyphProp[i].sva.fZeroWidth = 0;
3219 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)
3221 int i,k;
3222 IndicSyllable *syllables = NULL;
3223 int syllable_count = 0;
3224 BOOL modern = get_GSUB_Indic2(psa, psc);
3226 for (i = 0; i < cGlyphs; i++)
3228 int char_index[20];
3229 int char_count = 0;
3231 for (k = 0; k < cChars; k++)
3233 if (pwLogClust[k] == i)
3235 char_index[char_count] = k;
3236 char_count++;
3240 if (char_count == 0)
3242 FIXME("No chars in this glyph? Must be an error\n");
3243 continue;
3246 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3248 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3249 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3251 else
3252 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3254 pGlyphProp[i].sva.fClusterStart = 0;
3255 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3256 switch (lexical(pwcChars[char_index[k]]))
3258 case lex_Matra_pre:
3259 case lex_Matra_post:
3260 case lex_Matra_above:
3261 case lex_Matra_below:
3262 case lex_Modifier:
3263 break;
3264 default:
3265 pGlyphProp[i].sva.fClusterStart = 1;
3266 break;
3270 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3272 for (i = 0; i < syllable_count; i++)
3274 int j;
3275 WORD g = pwLogClust[syllables[i].start];
3276 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3278 if (pwLogClust[j] != g)
3280 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3281 pwLogClust[j] = g;
3286 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3287 HeapFree(GetProcessHeap(), 0, syllables);
3290 static void ShapeCharGlyphProp_Sinhala( 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 )
3292 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex);
3295 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 )
3297 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3300 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 )
3302 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3305 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 )
3307 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3310 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 )
3312 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3315 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 )
3317 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3320 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 )
3322 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3325 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 )
3327 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3330 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 )
3332 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3335 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 )
3337 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3340 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)
3342 if (ShapingData[psa->eScript].charGlyphPropProc)
3343 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3344 else
3345 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3348 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3350 if (ShapingData[psa->eScript].contextProc)
3351 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3354 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)
3356 int i;
3357 INT dirL;
3359 if (!rpRangeProperties)
3360 return;
3362 if (!psc->GSUB_Table)
3363 psc->GSUB_Table = load_gsub_table(hdc);
3365 if (!psc->GSUB_Table)
3366 return;
3368 if (!psa->fLogicalOrder && psa->fRTL)
3369 dirL = -1;
3370 else
3371 dirL = 1;
3373 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3375 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3376 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3380 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3382 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3383 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3385 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3388 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3390 const GSUB_Feature *feature;
3391 int i;
3393 if (!ShapingData[psa->eScript].requiredFeatures)
3394 return S_OK;
3396 if (!psc->GSUB_Table)
3397 psc->GSUB_Table = load_gsub_table(hdc);
3399 /* we need to have at least one of the required features */
3400 i = 0;
3401 while (ShapingData[psa->eScript].requiredFeatures[i])
3403 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3404 if (feature)
3405 return S_OK;
3406 i++;
3409 return USP_E_SCRIPT_NOT_IN_FONT;