usp10: Cache the script with the feature so that in caches with multiple scripts...
[wine/multimedia.git] / dlls / usp10 / shape.c
blob66d65c2d4b6509eb33ed10c1569d083cf4c6c235
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},
587 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
590 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
592 const GSUB_CoverageFormat1* cf1;
594 cf1 = table;
596 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
598 int count = GET_BE_WORD(cf1->GlyphCount);
599 int i;
600 TRACE("Coverage Format 1, %i glyphs\n",count);
601 for (i = 0; i < count; i++)
602 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
603 return i;
604 return -1;
606 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
608 const GSUB_CoverageFormat2* cf2;
609 int i;
610 int count;
611 cf2 = (const GSUB_CoverageFormat2*)cf1;
613 count = GET_BE_WORD(cf2->RangeCount);
614 TRACE("Coverage Format 2, %i ranges\n",count);
615 for (i = 0; i < count; i++)
617 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
618 return -1;
619 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
620 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
622 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
623 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
626 return -1;
628 else
629 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
631 return -1;
634 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
636 const GSUB_ScriptList *script;
637 const GSUB_Script *deflt = NULL;
638 int i;
639 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
641 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
642 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
644 const GSUB_Script *scr;
645 int offset;
647 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
648 scr = (const GSUB_Script*)((const BYTE*)script + offset);
650 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
651 return scr;
652 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
653 deflt = scr;
655 return deflt;
658 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
660 int i;
661 int offset;
662 const GSUB_LangSys *Lang;
664 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
666 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
668 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
669 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
671 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
672 return Lang;
674 offset = GET_BE_WORD(script->DefaultLangSys);
675 if (offset)
677 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
678 return Lang;
680 return NULL;
683 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
685 int i;
686 const GSUB_FeatureList *feature;
687 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
689 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
690 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
692 int index = GET_BE_WORD(lang->FeatureIndex[i]);
693 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
695 const GSUB_Feature *feat;
696 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
697 return feat;
700 return NULL;
703 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
705 int j;
706 TRACE("Single Substitution Subtable\n");
708 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
710 int offset;
711 const GSUB_SingleSubstFormat1 *ssf1;
712 offset = GET_BE_WORD(look->SubTable[j]);
713 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
714 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
716 int offset = GET_BE_WORD(ssf1->Coverage);
717 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
718 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
720 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
721 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
722 TRACE(" 0x%x\n",glyphs[glyph_index]);
723 return glyph_index + 1;
726 else
728 const GSUB_SingleSubstFormat2 *ssf2;
729 INT index;
730 INT offset;
732 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
733 offset = GET_BE_WORD(ssf1->Coverage);
734 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
735 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
736 TRACE(" Coverage index %i\n",index);
737 if (index != -1)
739 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
740 return GSUB_E_NOGLYPH;
742 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
743 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
744 TRACE("0x%x\n",glyphs[glyph_index]);
745 return glyph_index + 1;
749 return GSUB_E_NOGLYPH;
752 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
754 int j;
755 TRACE("Multiple Substitution Subtable\n");
757 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
759 int offset, index;
760 const GSUB_MultipleSubstFormat1 *msf1;
761 offset = GET_BE_WORD(look->SubTable[j]);
762 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
764 offset = GET_BE_WORD(msf1->Coverage);
765 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
766 if (index != -1)
768 const GSUB_Sequence *seq;
769 int sub_count;
770 int j;
771 offset = GET_BE_WORD(msf1->Sequence[index]);
772 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
773 sub_count = GET_BE_WORD(seq->GlyphCount);
774 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
776 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
777 glyphs[j] =glyphs[j-(sub_count-1)];
779 for (j = 0; j < sub_count; j++)
780 if (write_dir < 0)
781 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
782 else
783 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
785 *glyph_count = *glyph_count + (sub_count - 1);
787 if (TRACE_ON(uniscribe))
789 for (j = 0; j < sub_count; j++)
790 TRACE(" 0x%x",glyphs[glyph_index+j]);
791 TRACE("\n");
794 return glyph_index + sub_count;
797 return GSUB_E_NOGLYPH;
800 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
802 int j;
803 TRACE("Alternate Substitution Subtable\n");
805 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
807 int offset;
808 const GSUB_AlternateSubstFormat1 *asf1;
809 INT index;
811 offset = GET_BE_WORD(look->SubTable[j]);
812 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
813 offset = GET_BE_WORD(asf1->Coverage);
815 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
816 if (index != -1)
818 const GSUB_AlternateSet *as;
819 offset = GET_BE_WORD(asf1->AlternateSet[index]);
820 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
821 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
822 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
823 return GSUB_E_NOGLYPH;
825 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
826 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
827 TRACE(" 0x%x\n",glyphs[glyph_index]);
828 return glyph_index + 1;
831 return GSUB_E_NOGLYPH;
834 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
836 int j;
838 TRACE("Ligature Substitution Subtable\n");
839 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
841 const GSUB_LigatureSubstFormat1 *lsf1;
842 int offset,index;
844 offset = GET_BE_WORD(look->SubTable[j]);
845 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
846 offset = GET_BE_WORD(lsf1->Coverage);
847 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
848 TRACE(" Coverage index %i\n",index);
849 if (index != -1)
851 const GSUB_LigatureSet *ls;
852 int k, count;
854 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
855 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
856 count = GET_BE_WORD(ls->LigatureCount);
857 TRACE(" LigatureSet has %i members\n",count);
858 for (k = 0; k < count; k++)
860 const GSUB_Ligature *lig;
861 int CompCount,l,CompIndex;
863 offset = GET_BE_WORD(ls->Ligature[k]);
864 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
865 CompCount = GET_BE_WORD(lig->CompCount) - 1;
866 CompIndex = glyph_index+write_dir;
867 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
869 int CompGlyph;
870 CompGlyph = GET_BE_WORD(lig->Component[l]);
871 if (CompGlyph != glyphs[CompIndex])
872 break;
873 CompIndex += write_dir;
875 if (l == CompCount)
877 int replaceIdx = glyph_index;
878 if (write_dir < 0)
879 replaceIdx = glyph_index - CompCount;
881 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
882 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
883 TRACE("0x%x\n",glyphs[replaceIdx]);
884 if (CompCount > 0)
886 int j;
887 for (j = replaceIdx + 1; j < *glyph_count; j++)
888 glyphs[j] =glyphs[j+CompCount];
889 *glyph_count = *glyph_count - CompCount;
891 return replaceIdx + 1;
896 return GSUB_E_NOGLYPH;
899 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
901 int j;
902 BOOL done = FALSE;
904 TRACE("Chaining Contextual Substitution Subtable\n");
905 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
907 const GSUB_ChainContextSubstFormat1 *ccsf1;
908 int offset;
909 int dirLookahead = write_dir;
910 int dirBacktrack = -1 * write_dir;
912 offset = GET_BE_WORD(look->SubTable[j]);
913 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
914 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
916 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
917 continue;
919 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
921 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
922 continue;
924 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
926 int k;
927 int indexGlyphs;
928 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
929 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
930 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
931 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
932 int newIndex = glyph_index;
934 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
936 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
938 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
940 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
941 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
942 break;
944 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
945 continue;
946 TRACE("Matched Backtrack\n");
948 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
950 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
951 for (k = 0; k < indexGlyphs; k++)
953 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
954 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
955 break;
957 if (k != indexGlyphs)
958 continue;
959 TRACE("Matched IndexGlyphs\n");
961 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
963 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
965 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
966 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
967 break;
969 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
970 continue;
971 TRACE("Matched LookAhead\n");
973 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
975 if (GET_BE_WORD(ccsf3_4->SubstCount))
977 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
979 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
980 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
982 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
983 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
984 if (newIndex == -1)
986 ERR("Chain failed to generate a glyph\n");
987 continue;
990 return newIndex;
992 else return GSUB_E_NOGLYPH;
995 return -1;
998 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1000 int offset;
1001 const GSUB_LookupTable *look;
1003 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1004 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1005 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1006 switch(GET_BE_WORD(look->LookupType))
1008 case 1:
1009 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1010 case 2:
1011 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1012 case 3:
1013 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1014 case 4:
1015 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1016 case 6:
1017 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1018 default:
1019 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1021 return GSUB_E_NOGLYPH;
1024 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1026 int i;
1027 int out_index = GSUB_E_NOGLYPH;
1028 const GSUB_LookupList *lookup;
1030 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1032 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1033 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1035 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1036 if (out_index != GSUB_E_NOGLYPH)
1037 break;
1039 if (out_index == GSUB_E_NOGLYPH)
1040 TRACE("lookups found no glyphs\n");
1041 else
1043 int out2;
1044 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1045 if (out2!=GSUB_E_NOGLYPH)
1046 out_index = out2;
1048 return out_index;
1051 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1053 UINT charset;
1055 if (psc->userScript != 0)
1057 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1058 return ShapingData[psa->eScript].newOtTag;
1059 else
1060 return (char*)&psc->userScript;
1063 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1064 return ShapingData[psa->eScript].newOtTag;
1066 if (ShapingData[psa->eScript].otTag[0] != 0)
1067 return ShapingData[psa->eScript].otTag;
1070 * fall back to the font charset
1072 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1073 switch (charset)
1075 case ANSI_CHARSET: return "latn";
1076 case BALTIC_CHARSET: return "latn"; /* ?? */
1077 case CHINESEBIG5_CHARSET: return "hani";
1078 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1079 case GB2312_CHARSET: return "hani";
1080 case GREEK_CHARSET: return "grek";
1081 case HANGUL_CHARSET: return "hang";
1082 case RUSSIAN_CHARSET: return "cyrl";
1083 case SHIFTJIS_CHARSET: return "kana";
1084 case TURKISH_CHARSET: return "latn"; /* ?? */
1085 case VIETNAMESE_CHARSET: return "latn";
1086 case JOHAB_CHARSET: return "latn"; /* ?? */
1087 case ARABIC_CHARSET: return "arab";
1088 case HEBREW_CHARSET: return "hebr";
1089 case THAI_CHARSET: return "thai";
1090 default: return "latn";
1094 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1096 const GSUB_Feature *feature;
1097 const char* script;
1098 int i;
1100 script = get_opentype_script(hdc,psa,psc,FALSE);
1102 for (i = 0; i < psc->feature_count; i++)
1104 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1105 return psc->features[i].feature;
1108 feature = NULL;
1110 if (psc->GSUB_Table)
1112 const GSUB_Script *script;
1113 const GSUB_LangSys *language;
1114 int attempt = 2;
1118 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1119 attempt--;
1120 if (script)
1122 if (psc->userLang != 0)
1123 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1124 else
1125 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1126 if (language)
1127 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1129 } while(attempt && !feature);
1131 /* try in the default (latin) table */
1132 if (!feature)
1134 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1135 if (script)
1137 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1138 if (language)
1139 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1144 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1146 psc->feature_count++;
1148 if (psc->features)
1149 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1150 else
1151 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1153 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1154 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1155 psc->features[psc->feature_count - 1].feature = feature;
1156 return feature;
1159 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)
1161 const GSUB_Feature *feature;
1163 feature = load_GSUB_feature(hdc, psa, psc, feat);
1164 if (!feature)
1165 return GSUB_E_NOFEATURE;
1167 TRACE("applying feature %s\n",feat);
1168 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1171 static VOID *load_gsub_table(HDC hdc)
1173 VOID* GSUB_Table = NULL;
1174 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1175 if (length != GDI_ERROR)
1177 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1178 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1179 TRACE("Loaded GSUB table of %i bytes\n",length);
1181 return GSUB_Table;
1184 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)
1186 WORD *glyphs;
1187 INT glyph_count = count;
1188 INT rc;
1190 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1191 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1192 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1193 if (rc > GSUB_E_NOGLYPH)
1194 rc = count - glyph_count;
1195 else
1196 rc = 0;
1198 HeapFree(GetProcessHeap(),0,glyphs);
1199 return rc;
1202 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1204 int offset;
1205 WORD class = 0;
1206 const GDEF_ClassDefFormat1 *cf1;
1208 if (!header)
1209 return 0;
1211 offset = GET_BE_WORD(header->GlyphClassDef);
1212 if (!offset)
1213 return 0;
1215 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1216 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1218 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1220 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1221 if (index < GET_BE_WORD(cf1->GlyphCount))
1222 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1225 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1227 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1228 int i, top;
1229 top = GET_BE_WORD(cf2->ClassRangeCount);
1230 for (i = 0; i < top; i++)
1232 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1233 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1235 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1236 break;
1240 else
1241 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1243 return class;
1246 static VOID *load_gdef_table(HDC hdc)
1248 VOID* GDEF_Table = NULL;
1249 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1250 if (length != GDI_ERROR)
1252 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1253 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1254 TRACE("Loaded GDEF table of %i bytes\n",length);
1256 return GDEF_Table;
1259 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1261 int i;
1263 if (!psc->GDEF_Table)
1264 psc->GDEF_Table = load_gdef_table(hdc);
1266 for (i = 0; i < cGlyphs; i++)
1268 WORD class;
1270 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1272 switch (class)
1274 case 0:
1275 case BaseGlyph:
1276 pGlyphProp[i].sva.fClusterStart = 1;
1277 pGlyphProp[i].sva.fDiacritic = 0;
1278 pGlyphProp[i].sva.fZeroWidth = 0;
1279 break;
1280 case LigatureGlyph:
1281 pGlyphProp[i].sva.fClusterStart = 1;
1282 pGlyphProp[i].sva.fDiacritic = 0;
1283 pGlyphProp[i].sva.fZeroWidth = 0;
1284 break;
1285 case MarkGlyph:
1286 pGlyphProp[i].sva.fClusterStart = 0;
1287 pGlyphProp[i].sva.fDiacritic = 1;
1288 pGlyphProp[i].sva.fZeroWidth = 1;
1289 break;
1290 case ComponentGlyph:
1291 pGlyphProp[i].sva.fClusterStart = 0;
1292 pGlyphProp[i].sva.fDiacritic = 0;
1293 pGlyphProp[i].sva.fZeroWidth = 0;
1294 break;
1295 default:
1296 ERR("Unknown glyph class %i\n",class);
1297 pGlyphProp[i].sva.fClusterStart = 1;
1298 pGlyphProp[i].sva.fDiacritic = 0;
1299 pGlyphProp[i].sva.fZeroWidth = 0;
1304 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1306 int i;
1308 for (i = 0; i < cGlyphs; i++)
1310 if (!pGlyphProp[i].sva.fClusterStart)
1312 int j;
1313 for (j = 0; j < cChars; j++)
1315 if (pwLogClust[j] == i)
1317 int k = j;
1318 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1319 k-=1;
1320 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1321 pwLogClust[j] = pwLogClust[k];
1328 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1330 if (changeCount == 0)
1331 return;
1332 else
1334 int i;
1335 int target_glyph = nextIndex - 1;
1336 int seeking_glyph;
1337 int target_index = -1;
1338 int replacing_glyph = -1;
1339 int changed = 0;
1342 if (changeCount > 0)
1343 target_glyph = nextIndex - (changeCount+1);
1345 seeking_glyph = target_glyph;
1347 do {
1348 if (write_dir > 0)
1349 for (i = 0; i < chars; i++)
1351 if (pwLogClust[i] == seeking_glyph)
1353 target_index = i;
1354 break;
1357 else
1358 for (i = chars - 1; i >= 0; i--)
1360 if (pwLogClust[i] == seeking_glyph)
1362 target_index = i;
1363 break;
1366 if (target_index == -1)
1367 seeking_glyph ++;
1369 while (target_index == -1 && seeking_glyph < chars);
1371 if (target_index == -1)
1373 ERR("Unable to find target glyph\n");
1374 return;
1377 if (changeCount < 0)
1379 /* merge glyphs */
1380 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1382 if (pwLogClust[i] == target_glyph)
1383 continue;
1384 if(pwLogClust[i] == replacing_glyph)
1385 pwLogClust[i] = target_glyph;
1386 else
1388 changed--;
1389 if (changed >= changeCount)
1391 replacing_glyph = pwLogClust[i];
1392 pwLogClust[i] = target_glyph;
1394 else
1395 break;
1399 /* renumber trailing indexes*/
1400 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1402 if (pwLogClust[i] != target_glyph)
1403 pwLogClust[i] += changeCount;
1406 else
1408 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1409 pwLogClust[i] += changeCount;
1414 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 )
1416 int i;
1418 if (psc->GSUB_Table)
1420 const GSUB_Feature *feature;
1422 feature = load_GSUB_feature(hdc, psa, psc, feat);
1423 if (!feature)
1424 return GSUB_E_NOFEATURE;
1426 i = 0;
1427 TRACE("applying feature %s\n",debugstr_an(feat,4));
1428 while(i < *pcGlyphs)
1430 INT nextIndex;
1431 INT prevCount = *pcGlyphs;
1432 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1433 if (nextIndex > GSUB_E_NOGLYPH)
1435 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1436 i = nextIndex;
1438 else
1439 i++;
1441 return *pcGlyphs;
1443 return GSUB_E_NOFEATURE;
1446 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1448 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1451 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1453 if (i + delta < 0)
1454 return 0;
1455 if ( i+ delta >= cchLen)
1456 return 0;
1458 i += delta;
1460 return chars[i];
1463 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1465 if (i + delta < 0)
1467 if (psa->fLinkBefore)
1468 return jtR;
1469 else
1470 return jtU;
1472 if ( i+ delta >= cchLen)
1474 if (psa->fLinkAfter)
1475 return jtL;
1476 else
1477 return jtU;
1480 i += delta;
1482 if (context_type[i] == jtT)
1483 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1484 else
1485 return context_type[i];
1488 static inline BOOL right_join_causing(CHAR joining_type)
1490 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1493 static inline BOOL left_join_causing(CHAR joining_type)
1495 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1498 static inline BOOL word_break_causing(WCHAR chr)
1500 /* we are working within a string of characters already guareented to
1501 be within one script, Syriac, so we do not worry about any character
1502 other than the space character outside of that range */
1503 return (chr == 0 || chr == 0x20 );
1507 * ContextualShape_Arabic
1509 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1511 CHAR *context_type;
1512 INT *context_shape;
1513 INT dirR, dirL;
1514 int i;
1516 if (*pcGlyphs != cChars)
1518 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1519 return;
1522 if (!psa->fLogicalOrder && psa->fRTL)
1524 dirR = 1;
1525 dirL = -1;
1527 else
1529 dirR = -1;
1530 dirL = 1;
1533 if (!psc->GSUB_Table)
1534 psc->GSUB_Table = load_gsub_table(hdc);
1536 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1537 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1539 for (i = 0; i < cChars; i++)
1540 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1542 for (i = 0; i < cChars; i++)
1544 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1545 context_shape[i] = Xr;
1546 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1547 context_shape[i] = Xl;
1548 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)))
1549 context_shape[i] = Xm;
1550 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1551 context_shape[i] = Xr;
1552 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1553 context_shape[i] = Xl;
1554 else
1555 context_shape[i] = Xn;
1558 /* Contextual Shaping */
1559 i = 0;
1560 while(i < *pcGlyphs)
1562 BOOL shaped = FALSE;
1564 if (psc->GSUB_Table)
1566 INT nextIndex;
1567 INT prevCount = *pcGlyphs;
1568 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1569 if (nextIndex > GSUB_E_NOGLYPH)
1571 i = nextIndex;
1572 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1574 shaped = (nextIndex > GSUB_E_NOGLYPH);
1577 if (!shaped)
1579 if (context_shape[i] == Xn)
1581 WORD newGlyph = pwOutGlyphs[i];
1582 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1584 /* fall back to presentation form B */
1585 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1586 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1587 pwOutGlyphs[i] = newGlyph;
1590 i++;
1594 HeapFree(GetProcessHeap(),0,context_shape);
1595 HeapFree(GetProcessHeap(),0,context_type);
1599 * ContextualShape_Syriac
1602 #define ALAPH 0x710
1603 #define DALATH 0x715
1604 #define RISH 0x72A
1606 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1608 CHAR *context_type;
1609 INT *context_shape;
1610 INT dirR, dirL;
1611 int i;
1613 if (*pcGlyphs != cChars)
1615 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1616 return;
1619 if (!psa->fLogicalOrder && psa->fRTL)
1621 dirR = 1;
1622 dirL = -1;
1624 else
1626 dirR = -1;
1627 dirL = 1;
1630 if (!psc->GSUB_Table)
1631 psc->GSUB_Table = load_gsub_table(hdc);
1633 if (!psc->GSUB_Table)
1634 return;
1636 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1637 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1639 for (i = 0; i < cChars; i++)
1640 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1642 for (i = 0; i < cChars; i++)
1644 if (pwcChars[i] == ALAPH)
1646 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1648 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1649 context_shape[i] = Afj;
1650 else if ( rchar != DALATH && rchar != RISH &&
1651 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1652 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1653 context_shape[i] = Afn;
1654 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1655 context_shape[i] = Afx;
1656 else
1657 context_shape[i] = Xn;
1659 else if (context_type[i] == jtR &&
1660 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1661 context_shape[i] = Xr;
1662 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1663 context_shape[i] = Xl;
1664 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)))
1665 context_shape[i] = Xm;
1666 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1667 context_shape[i] = Xr;
1668 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1669 context_shape[i] = Xl;
1670 else
1671 context_shape[i] = Xn;
1674 /* Contextual Shaping */
1675 i = 0;
1676 while(i < *pcGlyphs)
1678 INT nextIndex;
1679 INT prevCount = *pcGlyphs;
1680 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1681 if (nextIndex > GSUB_E_NOGLYPH)
1683 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1684 i = nextIndex;
1686 else
1687 i++;
1690 HeapFree(GetProcessHeap(),0,context_shape);
1691 HeapFree(GetProcessHeap(),0,context_type);
1695 * ContextualShape_Phags_pa
1698 #define phags_pa_CANDRABINDU 0xA873
1699 #define phags_pa_START 0xA840
1700 #define phags_pa_END 0xA87F
1702 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1704 INT *context_shape;
1705 INT dirR, dirL;
1706 int i;
1708 if (*pcGlyphs != cChars)
1710 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1711 return;
1714 if (!psa->fLogicalOrder && psa->fRTL)
1716 dirR = 1;
1717 dirL = -1;
1719 else
1721 dirR = -1;
1722 dirL = 1;
1725 if (!psc->GSUB_Table)
1726 psc->GSUB_Table = load_gsub_table(hdc);
1728 if (!psc->GSUB_Table)
1729 return;
1731 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1733 for (i = 0; i < cChars; i++)
1735 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1737 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1738 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1739 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1740 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1742 if (jrchar && jlchar)
1743 context_shape[i] = Xm;
1744 else if (jrchar)
1745 context_shape[i] = Xr;
1746 else if (jlchar)
1747 context_shape[i] = Xl;
1748 else
1749 context_shape[i] = Xn;
1751 else
1752 context_shape[i] = -1;
1755 /* Contextual Shaping */
1756 i = 0;
1757 while(i < *pcGlyphs)
1759 if (context_shape[i] >= 0)
1761 INT nextIndex;
1762 INT prevCount = *pcGlyphs;
1763 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1764 if (nextIndex > GSUB_E_NOGLYPH)
1766 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1767 i = nextIndex;
1769 else
1770 i++;
1772 else
1773 i++;
1776 HeapFree(GetProcessHeap(),0,context_shape);
1779 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1781 int i;
1783 /* Replace */
1784 pwOutChars[cWalk] = replacements[0];
1785 cWalk=cWalk+1;
1787 /* Insert */
1788 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1790 int j;
1791 for (j = *pcChars; j > cWalk; j--)
1792 pwOutChars[j] = pwOutChars[j-1];
1793 *pcChars= *pcChars+1;
1794 pwOutChars[cWalk] = replacements[i];
1795 cWalk = cWalk+1;
1799 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust)
1801 int i;
1802 int cWalk;
1803 int offset = 0;
1805 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1807 for (i = 0; vowels[i].base != 0x0; i++)
1809 if (pwOutChars[cWalk] == vowels[i].base)
1811 int j;
1812 int o = 1;
1813 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1814 if (vowels[i].parts[1]) { cWalk++; o++; }
1815 if (vowels[i].parts[2]) { cWalk++; o++; }
1816 offset += o;
1817 for (j = (cWalk - offset) + 1; j < *pcChars - offset; j ++)
1818 pwLogClust[j]+=o;
1819 break;
1825 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1827 int i;
1828 int offset = 0;
1829 int cWalk;
1831 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1833 for (i = 0; consonants[i].output!= 0x0; i++)
1835 int j;
1836 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1837 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1838 break;
1840 if (consonants[i].parts[j]==0x0) /* matched all */
1842 int k;
1843 j--;
1844 pwOutChars[cWalk] = consonants[i].output;
1845 for(k = cWalk+1; k < *pcChars - j; k++)
1846 pwOutChars[k] = pwOutChars[k+j];
1847 *pcChars = *pcChars - j;
1848 for (k = j ; k > 0; k--)
1849 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1850 offset += j;
1851 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1852 pwLogClust[k]--;
1853 break;
1856 cWalk++;
1860 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1862 if (s->ralf >= 0)
1864 int j;
1865 WORD Ra = pwChar[s->start];
1866 WORD H = pwChar[s->start+1];
1868 TRACE("Doing reorder of Ra to %i\n",s->base);
1869 for (j = s->start; j < s->base-1; j++)
1870 pwChar[j] = pwChar[j+2];
1871 pwChar[s->base-1] = Ra;
1872 pwChar[s->base] = H;
1874 s->ralf = s->base-1;
1875 s->base -= 2;
1879 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1881 if (s->ralf >= 0)
1883 int j,loc;
1884 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1885 WORD Ra = pwChar[s->start];
1886 WORD H = pwChar[s->start+1];
1887 for (loc = s->end; loc > stop; loc--)
1888 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1889 break;
1891 TRACE("Doing reorder of Ra to %i\n",loc);
1892 for (j = s->start; j < loc-1; j++)
1893 pwChar[j] = pwChar[j+2];
1894 pwChar[loc-1] = Ra;
1895 pwChar[loc] = H;
1897 s->ralf = loc-1;
1898 s->base -= 2;
1899 if (s->blwf >= 0) s->blwf -= 2;
1900 if (s->pref >= 0) s->pref -= 2;
1904 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1906 if (s->ralf >= 0)
1908 int j;
1909 WORD Ra = pwChar[s->start];
1910 WORD H = pwChar[s->start+1];
1912 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1913 for (j = s->start; j < s->end-1; j++)
1914 pwChar[j] = pwChar[j+2];
1915 pwChar[s->end-1] = Ra;
1916 pwChar[s->end] = H;
1918 s->ralf = s->end-1;
1919 s->base -= 2;
1920 if (s->blwf >= 0) s->blwf -= 2;
1921 if (s->pref >= 0) s->pref -= 2;
1925 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1927 int i;
1929 /* reorder Matras */
1930 if (s->end > s->base)
1932 for (i = 1; i <= s->end-s->base; i++)
1934 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1936 int j;
1937 WCHAR c = pwChar[s->base+i];
1938 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1939 for (j = s->base+i; j > s->base; j--)
1940 pwChar[j] = pwChar[j-1];
1941 pwChar[s->base] = c;
1943 if (s->ralf >= s->base) s->ralf++;
1944 if (s->blwf >= s->base) s->blwf++;
1945 if (s->pref >= s->base) s->pref++;
1946 s->base ++;
1952 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1954 int i;
1956 /* reorder Matras */
1957 if (s->end > s->base)
1959 for (i = 1; i <= s->end-s->base; i++)
1961 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1963 int j;
1964 WCHAR c = pwChar[s->base+i];
1965 TRACE("Doing reorder of %x to %i\n",c,s->start);
1966 for (j = s->base+i; j > s->start; j--)
1967 pwChar[j] = pwChar[j-1];
1968 pwChar[s->start] = c;
1970 if (s->ralf >= 0) s->ralf++;
1971 if (s->blwf >= 0) s->blwf++;
1972 if (s->pref >= 0) s->pref++;
1973 s->base ++;
1979 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1981 if (s->blwf >= 0 && g->blwf > g->base)
1983 int j,loc;
1984 int g_offset;
1985 for (loc = s->end; loc > s->blwf; loc--)
1986 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1987 break;
1989 g_offset = (loc - s->blwf) - 1;
1991 if (loc != s->blwf)
1993 WORD blwf = glyphs[g->blwf];
1994 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1995 /* do not care about the pwChar array anymore, just the glyphs */
1996 for (j = 0; j < g_offset; j++)
1997 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1998 glyphs[g->blwf + g_offset] = blwf;
2003 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2005 int i;
2007 /* reorder previously moved Matras to correct position*/
2008 for (i = s->start; i < s->base; i++)
2010 if (lexical(pwChar[i]) == lex_Matra_pre)
2012 int j;
2013 int g_start = g->start + i - s->start;
2014 if (g_start < g->base -1 )
2016 WCHAR og = glyphs[g_start];
2017 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2018 for (j = g_start; j < g->base-1; j++)
2019 glyphs[j] = glyphs[j+1];
2020 glyphs[g->base-1] = og;
2026 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2028 if (s->pref >= 0 && g->pref > g->base)
2030 int j;
2031 WCHAR og = glyphs[g->pref];
2032 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2033 for (j = g->pref; j > g->base; j--)
2034 glyphs[j] = glyphs[j-1];
2035 glyphs[g->base] = og;
2039 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2041 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2042 if (s->start == s->base && s->base == s->end) return;
2043 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2045 Reorder_Ra_follows_base(pwChar, s, lexical);
2046 Reorder_Matra_precede_base(pwChar, s, lexical);
2049 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2051 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2052 if (s->start == s->base && s->base == s->end) return;
2053 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2055 Reorder_Ra_follows_matra(pwChar, s, lexical);
2056 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2059 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2061 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2062 if (s->start == s->base && s->base == s->end) return;
2063 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2065 Reorder_Ra_follows_base(pwChar, s, lexical);
2066 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2069 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2071 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2072 if (s->start == s->base && s->base == s->end) return;
2073 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2075 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2076 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2079 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2081 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2082 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2083 if (s->start == s->base && s->base == s->end) return;
2084 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2086 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2089 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2091 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2092 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2093 if (s->start == s->base && s->base == s->end) return;
2094 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2096 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2097 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2101 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2103 if (shift == 0)
2104 return;
2106 if (glyph_index->start > index)
2107 glyph_index->start += shift;
2108 if (glyph_index->base > index)
2109 glyph_index->base+= shift;
2110 if (glyph_index->end > index)
2111 glyph_index->end+= shift;
2112 if (glyph_index->ralf > index)
2113 glyph_index->ralf+= shift;
2114 if (glyph_index->blwf > index)
2115 glyph_index->blwf+= shift;
2116 if (glyph_index->pref > index)
2117 glyph_index->pref+= shift;
2120 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 )
2122 int index = glyph_index->start;
2124 if (!feature)
2125 return;
2127 while(index <= glyph_index->end)
2129 INT nextIndex;
2130 INT prevCount = *pcGlyphs;
2131 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2132 if (nextIndex > GSUB_E_NOGLYPH)
2134 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2135 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2136 index = nextIndex;
2138 else
2139 index++;
2143 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2145 int i = 0;
2146 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)))))
2147 i++;
2148 if (index + i <= end-1)
2149 return index + i;
2150 else
2151 return -1;
2154 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)
2156 INT index, nextIndex;
2157 INT count,g_offset;
2159 count = syllable->base - syllable->start;
2161 g_offset = 0;
2162 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2163 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2165 INT prevCount = *pcGlyphs;
2166 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2167 if (nextIndex > GSUB_E_NOGLYPH)
2169 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2170 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2171 g_offset += (*pcGlyphs - prevCount);
2174 index+=2;
2175 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2179 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)
2181 INT nextIndex;
2182 INT prevCount = *pcGlyphs;
2184 if (syllable->ralf >= 0)
2186 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2187 if (nextIndex > GSUB_E_NOGLYPH)
2189 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2190 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2195 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2197 int i = 0;
2198 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2199 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2200 is_consonant(lexical(pwChars[index+i+1])))))
2201 i++;
2202 if (index + i <= end-1)
2203 return index+i;
2204 else
2205 return -1;
2208 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)
2210 INT index, nextIndex;
2211 INT count, g_offset=0;
2212 INT ralf = syllable->ralf;
2214 count = syllable->end - syllable->base;
2216 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2218 while (index >= 0)
2220 INT prevCount = *pcGlyphs;
2221 if (ralf >=0 && ralf < index)
2223 g_offset--;
2224 ralf = -1;
2227 if (!modern)
2229 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2230 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2231 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2234 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2235 if (nextIndex > GSUB_E_NOGLYPH)
2237 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2238 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2239 g_offset += (*pcGlyphs - prevCount);
2241 else if (!modern)
2243 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2244 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2245 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2248 index+=2;
2249 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2253 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)
2255 int c;
2256 int overall_shift = 0;
2257 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2258 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2259 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2260 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2261 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2262 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2263 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2264 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2265 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2266 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2267 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2268 IndicSyllable glyph_indexs;
2270 for (c = 0; c < syllable_count; c++)
2272 int old_end;
2273 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2274 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2275 old_end = glyph_indexs.end;
2277 if (locl)
2279 TRACE("applying feature locl\n");
2280 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2282 if (nukt)
2284 TRACE("applying feature nukt\n");
2285 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2287 if (akhn)
2289 TRACE("applying feature akhn\n");
2290 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2293 if (rphf)
2294 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2295 if (rkrf)
2297 TRACE("applying feature rkrf\n");
2298 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2300 if (pref)
2301 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2302 if (blwf)
2304 if (!modern)
2305 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2307 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2310 if (half)
2311 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2312 if (pstf)
2314 TRACE("applying feature pstf\n");
2315 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2317 if (vatu)
2319 TRACE("applying feature vatu\n");
2320 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2322 if (cjct)
2324 TRACE("applying feature cjct\n");
2325 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2328 if (second_reorder)
2329 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2331 overall_shift += glyph_indexs.end - old_end;
2335 static inline int unicode_lex(WCHAR c)
2337 int type;
2339 if (!c) return lex_Generic;
2340 if (c == 0x200D) return lex_ZWJ;
2341 if (c == 0x200C) return lex_ZWNJ;
2342 if (c == 0x00A0) return lex_NBSP;
2344 type = get_table_entry( indic_syllabic_table, c );
2346 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2348 switch( type )
2350 case 0x0d07: /* Unknown */
2351 case 0x0e07: /* Unknwon */
2352 default: return lex_Generic;
2353 case 0x0001:
2354 case 0x0002:
2355 case 0x0011:
2356 case 0x0012:
2357 case 0x0013:
2358 case 0x0014: return lex_Modifier;
2359 case 0x0003:
2360 case 0x0009:
2361 case 0x000a:
2362 case 0x000b:
2363 case 0x000d:
2364 case 0x000e:
2365 case 0x000f:
2366 case 0x0010: return lex_Consonant;
2367 case 0x0004: return lex_Nukta;
2368 case 0x0005: return lex_Halant;
2369 case 0x0006:
2370 case 0x0008: return lex_Vowel;
2371 case 0x0007:
2372 case 0x0107: return lex_Matra_post;
2373 case 0x0207:
2374 case 0x0307: return lex_Matra_pre;
2375 case 0x0807:
2376 case 0x0907:
2377 case 0x0a07:
2378 case 0x0b07:
2379 case 0x0c07:
2380 case 0x0407: return lex_Composed_Vowel;
2381 case 0x0507: return lex_Matra_above;
2382 case 0x0607: return lex_Matra_below;
2383 case 0x000c: return lex_Ra;
2387 static int sinhala_lex(WCHAR c)
2389 switch (c)
2391 case 0x0DDA:
2392 case 0x0DDD:
2393 case 0x0DDC:
2394 case 0x0DDE: return lex_Matra_post;
2395 default:
2396 return unicode_lex(c);
2400 static const VowelComponents Sinhala_vowels[] = {
2401 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2402 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2403 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2404 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2405 {0x0000, {0x0000,0x0000,0x0}}};
2407 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2409 int cCount = cChars;
2410 int i;
2411 WCHAR *input;
2412 IndicSyllable *syllables = NULL;
2413 int syllable_count = 0;
2415 if (*pcGlyphs != cChars)
2417 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2418 return;
2421 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2423 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2425 /* Step 1: Decompose multi part vowels */
2426 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust);
2428 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2430 /* Step 2: Reorder within Syllables */
2431 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2432 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2434 /* Step 3: Strip dangling joiners */
2435 for (i = 0; i < cCount; i++)
2437 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2438 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2439 input[i] = 0x0020;
2442 /* Step 4: Base Form application to syllables */
2443 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2444 *pcGlyphs = cCount;
2445 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2447 HeapFree(GetProcessHeap(),0,input);
2448 HeapFree(GetProcessHeap(),0,syllables);
2451 static int devanagari_lex(WCHAR c)
2453 switch (c)
2455 case 0x0930: return lex_Ra;
2456 default:
2457 return unicode_lex(c);
2461 static const ConsonantComponents Devanagari_consonants[] ={
2462 {{0x0928, 0x093C, 0x00000}, 0x0929},
2463 {{0x0930, 0x093C, 0x00000}, 0x0931},
2464 {{0x0933, 0x093C, 0x00000}, 0x0934},
2465 {{0x0915, 0x093C, 0x00000}, 0x0958},
2466 {{0x0916, 0x093C, 0x00000}, 0x0959},
2467 {{0x0917, 0x093C, 0x00000}, 0x095A},
2468 {{0x091C, 0x093C, 0x00000}, 0x095B},
2469 {{0x0921, 0x093C, 0x00000}, 0x095C},
2470 {{0x0922, 0x093C, 0x00000}, 0x095D},
2471 {{0x092B, 0x093C, 0x00000}, 0x095E},
2472 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2474 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2476 int cCount = cChars;
2477 WCHAR *input;
2478 IndicSyllable *syllables = NULL;
2479 int syllable_count = 0;
2480 BOOL modern = get_GSUB_Indic2(psa, psc);
2482 if (*pcGlyphs != cChars)
2484 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2485 return;
2488 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2489 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2491 /* Step 1: Compose Consonant and Nukta */
2492 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2493 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2495 /* Step 2: Reorder within Syllables */
2496 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2497 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2498 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2499 *pcGlyphs = cCount;
2501 /* Step 3: Base Form application to syllables */
2502 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2504 HeapFree(GetProcessHeap(),0,input);
2505 HeapFree(GetProcessHeap(),0,syllables);
2508 static int bengali_lex(WCHAR c)
2510 switch (c)
2512 case 0x09B0: return lex_Ra;
2513 default:
2514 return unicode_lex(c);
2518 static const VowelComponents Bengali_vowels[] = {
2519 {0x09CB, {0x09C7,0x09BE,0x0000}},
2520 {0x09CC, {0x09C7,0x09D7,0x0000}},
2521 {0x0000, {0x0000,0x0000,0x0000}}};
2523 static const ConsonantComponents Bengali_consonants[] = {
2524 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2525 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2526 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2527 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2528 {{0x0000,0x0000,0x0000}, 0x0000}};
2530 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2532 int cCount = cChars;
2533 WCHAR *input;
2534 IndicSyllable *syllables = NULL;
2535 int syllable_count = 0;
2536 BOOL modern = get_GSUB_Indic2(psa, psc);
2538 if (*pcGlyphs != cChars)
2540 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2541 return;
2544 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2545 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2547 /* Step 1: Decompose Vowels and Compose Consonents */
2548 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust);
2549 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2550 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2552 /* Step 2: Reorder within Syllables */
2553 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2554 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2555 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2556 *pcGlyphs = cCount;
2558 /* Step 3: Initial form is only applied to the beginning of words */
2559 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2561 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2563 int index = cCount;
2564 int gCount = 1;
2565 if (index > 0) index++;
2567 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2571 /* Step 4: Base Form application to syllables */
2572 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2574 HeapFree(GetProcessHeap(),0,input);
2575 HeapFree(GetProcessHeap(),0,syllables);
2578 static int gurmukhi_lex(WCHAR c)
2580 return unicode_lex(c);
2583 static const ConsonantComponents Gurmukhi_consonants[] = {
2584 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2585 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2586 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2587 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2588 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2589 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2590 {{0x0000,0x0000,0x0000}, 0x0000}};
2592 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2594 int cCount = cChars;
2595 WCHAR *input;
2596 IndicSyllable *syllables = NULL;
2597 int syllable_count = 0;
2598 BOOL modern = get_GSUB_Indic2(psa, psc);
2600 if (*pcGlyphs != cChars)
2602 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2603 return;
2606 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2607 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2609 /* Step 1: Compose Consonents */
2610 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2611 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2613 /* Step 2: Reorder within Syllables */
2614 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2615 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2616 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2617 *pcGlyphs = cCount;
2619 /* Step 3: Base Form application to syllables */
2620 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2622 HeapFree(GetProcessHeap(),0,input);
2623 HeapFree(GetProcessHeap(),0,syllables);
2626 static int gujarati_lex(WCHAR c)
2628 switch (c)
2630 case 0x0AB0: return lex_Ra;
2631 default:
2632 return unicode_lex(c);
2636 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2638 int cCount = cChars;
2639 WCHAR *input;
2640 IndicSyllable *syllables = NULL;
2641 int syllable_count = 0;
2642 BOOL modern = get_GSUB_Indic2(psa, psc);
2644 if (*pcGlyphs != cChars)
2646 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2647 return;
2650 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2651 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2653 /* Step 1: Reorder within Syllables */
2654 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2655 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2656 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2657 *pcGlyphs = cCount;
2659 /* Step 2: Base Form application to syllables */
2660 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2662 HeapFree(GetProcessHeap(),0,input);
2663 HeapFree(GetProcessHeap(),0,syllables);
2666 static int oriya_lex(WCHAR c)
2668 switch (c)
2670 case 0x0B30: return lex_Ra;
2671 default:
2672 return unicode_lex(c);
2676 static const VowelComponents Oriya_vowels[] = {
2677 {0x0B48, {0x0B47,0x0B56,0x0000}},
2678 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2679 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2680 {0x0000, {0x0000,0x0000,0x0000}}};
2682 static const ConsonantComponents Oriya_consonants[] = {
2683 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2684 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2685 {{0x0000,0x0000,0x0000}, 0x0000}};
2687 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2689 int cCount = cChars;
2690 WCHAR *input;
2691 IndicSyllable *syllables = NULL;
2692 int syllable_count = 0;
2693 BOOL modern = get_GSUB_Indic2(psa, psc);
2695 if (*pcGlyphs != cChars)
2697 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2698 return;
2701 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2702 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2704 /* Step 1: Decompose Vowels and Compose Consonents */
2705 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust);
2706 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2707 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2709 /* Step 2: Reorder within Syllables */
2710 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2711 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2712 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2713 *pcGlyphs = cCount;
2715 /* Step 3: Base Form application to syllables */
2716 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2718 HeapFree(GetProcessHeap(),0,input);
2719 HeapFree(GetProcessHeap(),0,syllables);
2722 static int tamil_lex(WCHAR c)
2724 return unicode_lex(c);
2727 static const VowelComponents Tamil_vowels[] = {
2728 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2729 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2730 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2731 {0x0000, {0x0000,0x0000,0x0000}}};
2733 static const ConsonantComponents Tamil_consonants[] = {
2734 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2735 {{0x0000,0x0000,0x0000}, 0x0000}};
2737 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2739 int cCount = cChars;
2740 WCHAR *input;
2741 IndicSyllable *syllables = NULL;
2742 int syllable_count = 0;
2743 BOOL modern = get_GSUB_Indic2(psa, psc);
2745 if (*pcGlyphs != cChars)
2747 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2748 return;
2751 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2752 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2754 /* Step 1: Decompose Vowels and Compose Consonents */
2755 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust);
2756 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2757 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2759 /* Step 2: Reorder within Syllables */
2760 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2761 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2762 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2763 *pcGlyphs = cCount;
2765 /* Step 3: Base Form application to syllables */
2766 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2768 HeapFree(GetProcessHeap(),0,input);
2769 HeapFree(GetProcessHeap(),0,syllables);
2772 static int telugu_lex(WCHAR c)
2774 switch (c)
2776 case 0x0C43:
2777 case 0x0C44: return lex_Modifier;
2778 default:
2779 return unicode_lex(c);
2783 static const VowelComponents Telugu_vowels[] = {
2784 {0x0C48, {0x0C46,0x0C56,0x0000}},
2785 {0x0000, {0x0000,0x0000,0x0000}}};
2787 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2789 int cCount = cChars;
2790 WCHAR *input;
2791 IndicSyllable *syllables = NULL;
2792 int syllable_count = 0;
2793 BOOL modern = get_GSUB_Indic2(psa, psc);
2795 if (*pcGlyphs != cChars)
2797 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2798 return;
2801 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2802 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2804 /* Step 1: Decompose Vowels */
2805 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust);
2806 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2808 /* Step 2: Reorder within Syllables */
2809 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2810 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2811 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2812 *pcGlyphs = cCount;
2814 /* Step 3: Base Form application to syllables */
2815 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2817 HeapFree(GetProcessHeap(),0,input);
2818 HeapFree(GetProcessHeap(),0,syllables);
2821 static int kannada_lex(WCHAR c)
2823 switch (c)
2825 case 0x0CB0: return lex_Ra;
2826 default:
2827 return unicode_lex(c);
2831 static const VowelComponents Kannada_vowels[] = {
2832 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2833 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2834 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2835 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2836 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2837 {0x0000, {0x0000,0x0000,0x0000}}};
2839 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2841 int cCount = cChars;
2842 WCHAR *input;
2843 IndicSyllable *syllables = NULL;
2844 int syllable_count = 0;
2845 BOOL modern = get_GSUB_Indic2(psa, psc);
2847 if (*pcGlyphs != cChars)
2849 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2850 return;
2853 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2854 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2856 /* Step 1: Decompose Vowels */
2857 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust);
2858 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2860 /* Step 2: Reorder within Syllables */
2861 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2862 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2863 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2864 *pcGlyphs = cCount;
2866 /* Step 3: Base Form application to syllables */
2867 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2869 HeapFree(GetProcessHeap(),0,input);
2870 HeapFree(GetProcessHeap(),0,syllables);
2873 static int malayalam_lex(WCHAR c)
2875 return unicode_lex(c);
2878 static const VowelComponents Malayalam_vowels[] = {
2879 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2880 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2881 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2882 {0x0000, {0x0000,0x0000,0x0000}}};
2884 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2886 int cCount = cChars;
2887 WCHAR *input;
2888 IndicSyllable *syllables = NULL;
2889 int syllable_count = 0;
2890 BOOL modern = get_GSUB_Indic2(psa, psc);
2892 if (*pcGlyphs != cChars)
2894 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2895 return;
2898 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2899 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2901 /* Step 1: Decompose Vowels */
2902 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust);
2903 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2905 /* Step 2: Reorder within Syllables */
2906 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2907 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2908 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2909 *pcGlyphs = cCount;
2911 /* Step 3: Base Form application to syllables */
2912 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2914 HeapFree(GetProcessHeap(),0,input);
2915 HeapFree(GetProcessHeap(),0,syllables);
2918 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)
2920 int i,k;
2922 for (i = 0; i < cGlyphs; i++)
2924 int char_index[20];
2925 int char_count = 0;
2927 for (k = 0; k < cChars; k++)
2929 if (pwLogClust[k] == i)
2931 char_index[char_count] = k;
2932 char_count++;
2936 if (char_count == 0)
2938 FIXME("No chars in this glyph? Must be an error\n");
2939 continue;
2942 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2944 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2945 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2947 else
2948 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2951 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2952 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2955 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 )
2957 int i,k;
2958 int initGlyph, finaGlyph;
2959 INT dirR, dirL;
2960 BYTE *spaces;
2962 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2963 memset(spaces,0,cGlyphs);
2965 if (!psa->fLogicalOrder && psa->fRTL)
2967 initGlyph = cGlyphs-1;
2968 finaGlyph = 0;
2969 dirR = 1;
2970 dirL = -1;
2972 else
2974 initGlyph = 0;
2975 finaGlyph = cGlyphs-1;
2976 dirR = -1;
2977 dirL = 1;
2980 for (i = 0; i < cGlyphs; i++)
2982 for (k = 0; k < cChars; k++)
2983 if (pwLogClust[k] == i)
2985 if (pwcChars[k] == 0x0020)
2986 spaces[i] = 1;
2990 for (i = 0; i < cGlyphs; i++)
2992 int char_index[20];
2993 int char_count = 0;
2994 BOOL isInit, isFinal;
2996 for (k = 0; k < cChars; k++)
2998 if (pwLogClust[k] == i)
3000 char_index[char_count] = k;
3001 char_count++;
3005 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3006 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3008 if (char_count == 0)
3010 FIXME("No chars in this glyph? Must be an error\n");
3011 continue;
3014 if (char_count == 1)
3016 if (pwcChars[char_index[0]] == 0x0020) /* space */
3018 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3019 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3021 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3022 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3023 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3025 if (!isInit && !isFinal)
3026 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3027 else if (isInit)
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3029 else
3030 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3032 else if (!isInit)
3034 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3035 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3036 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3037 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3038 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3039 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3040 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3041 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3042 else
3043 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3045 else if (!isInit && !isFinal)
3046 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3047 else
3048 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3050 else if (char_count == 2)
3052 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3053 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3054 else if (!isInit)
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3056 else
3057 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3059 else if (!isInit && !isFinal)
3060 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3061 else
3062 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3065 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3066 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3067 HeapFree(GetProcessHeap(),0,spaces);
3070 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 )
3072 int i,k;
3073 int finaGlyph;
3074 INT dirL;
3075 BYTE *spaces;
3077 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3078 memset(spaces,0,cGlyphs);
3080 if (!psa->fLogicalOrder && psa->fRTL)
3082 finaGlyph = 0;
3083 dirL = -1;
3085 else
3087 finaGlyph = cGlyphs-1;
3088 dirL = 1;
3091 for (i = 0; i < cGlyphs; i++)
3093 for (k = 0; k < cChars; k++)
3094 if (pwLogClust[k] == i)
3096 if (pwcChars[k] == 0x0020)
3097 spaces[i] = 1;
3101 for (i = 0; i < cGlyphs; i++)
3103 int char_index[20];
3104 int char_count = 0;
3106 for (k = 0; k < cChars; k++)
3108 if (pwLogClust[k] == i)
3110 char_index[char_count] = k;
3111 char_count++;
3115 if (char_count == 0)
3117 FIXME("No chars in this glyph? Must be an error\n");
3118 continue;
3121 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3123 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3124 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3126 else if (i == finaGlyph)
3127 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3128 else
3129 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3132 HeapFree(GetProcessHeap(),0,spaces);
3133 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3134 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3136 /* Do not allow justification between marks and their base */
3137 for (i = 0; i < cGlyphs; i++)
3139 if (!pGlyphProp[i].sva.fClusterStart)
3140 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3144 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)
3146 int i,k;
3148 for (i = 0; i < cGlyphs; i++)
3150 int char_index[20];
3151 int char_count = 0;
3153 for (k = 0; k < cChars; k++)
3155 if (pwLogClust[k] == i)
3157 char_index[char_count] = k;
3158 char_count++;
3162 if (char_count == 0)
3164 FIXME("No chars in this glyph? Must be an error\n");
3165 continue;
3168 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3170 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3171 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3173 else
3174 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3176 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3177 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3180 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)
3182 int i,k;
3184 for (i = 0; i < cGlyphs; i++)
3186 int char_index[20];
3187 int char_count = 0;
3189 for (k = 0; k < cChars; k++)
3191 if (pwLogClust[k] == i)
3193 char_index[char_count] = k;
3194 char_count++;
3198 if (char_count == 0)
3200 FIXME("No chars in this glyph? Must be an error\n");
3201 continue;
3204 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3206 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3207 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3209 else
3210 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3212 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3213 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3215 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3216 for (i = 0; i < cGlyphs; i++)
3218 if (!pGlyphProp[i].sva.fClusterStart)
3220 pGlyphProp[i].sva.fDiacritic = 0;
3221 pGlyphProp[i].sva.fZeroWidth = 0;
3226 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)
3228 int i,k;
3229 IndicSyllable *syllables = NULL;
3230 int syllable_count = 0;
3231 BOOL modern = get_GSUB_Indic2(psa, psc);
3233 for (i = 0; i < cGlyphs; i++)
3235 int char_index[20];
3236 int char_count = 0;
3238 for (k = 0; k < cChars; k++)
3240 if (pwLogClust[k] == i)
3242 char_index[char_count] = k;
3243 char_count++;
3247 if (char_count == 0)
3249 FIXME("No chars in this glyph? Must be an error\n");
3250 continue;
3253 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3255 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3256 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3258 else
3259 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3261 pGlyphProp[i].sva.fClusterStart = 0;
3262 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3263 switch (lexical(pwcChars[char_index[k]]))
3265 case lex_Matra_pre:
3266 case lex_Matra_post:
3267 case lex_Matra_above:
3268 case lex_Matra_below:
3269 case lex_Modifier:
3270 break;
3271 default:
3272 pGlyphProp[i].sva.fClusterStart = 1;
3273 break;
3277 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3279 for (i = 0; i < syllable_count; i++)
3281 int j;
3282 WORD g = pwLogClust[syllables[i].start];
3283 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3285 if (pwLogClust[j] != g)
3287 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3288 pwLogClust[j] = g;
3293 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3294 HeapFree(GetProcessHeap(), 0, syllables);
3297 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 )
3299 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex);
3302 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 )
3304 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3307 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 )
3309 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3312 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 )
3314 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3317 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 )
3319 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3322 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 )
3324 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3327 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 )
3329 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3332 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 )
3334 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3337 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 )
3339 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3342 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 )
3344 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3347 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)
3349 if (ShapingData[psa->eScript].charGlyphPropProc)
3350 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3351 else
3352 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3355 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3357 if (ShapingData[psa->eScript].contextProc)
3358 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3361 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)
3363 int i;
3364 INT dirL;
3366 if (!rpRangeProperties)
3367 return;
3369 if (!psc->GSUB_Table)
3370 psc->GSUB_Table = load_gsub_table(hdc);
3372 if (!psc->GSUB_Table)
3373 return;
3375 if (!psa->fLogicalOrder && psa->fRTL)
3376 dirL = -1;
3377 else
3378 dirL = 1;
3380 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3382 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3383 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3387 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3389 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3390 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3392 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3395 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3397 const GSUB_Feature *feature;
3398 int i;
3400 if (!ShapingData[psa->eScript].requiredFeatures)
3401 return S_OK;
3403 if (!psc->GSUB_Table)
3404 psc->GSUB_Table = load_gsub_table(hdc);
3406 /* we need to have at least one of the required features */
3407 i = 0;
3408 while (ShapingData[psa->eScript].requiredFeatures[i])
3410 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3411 if (feature)
3412 return S_OK;
3413 i++;
3416 return USP_E_SCRIPT_NOT_IN_FONT;