usp10: In Arabic only fallback to presentation form B for isolated glyphs.
[wine.git] / dlls / usp10 / shape.c
blobbd383b99d6e22af2d84f0e93d09efcd31d7d15d6
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},
587 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
589 const GSUB_CoverageFormat1* cf1;
591 cf1 = table;
593 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
595 int count = GET_BE_WORD(cf1->GlyphCount);
596 int i;
597 TRACE("Coverage Format 1, %i glyphs\n",count);
598 for (i = 0; i < count; i++)
599 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
600 return i;
601 return -1;
603 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
605 const GSUB_CoverageFormat2* cf2;
606 int i;
607 int count;
608 cf2 = (const GSUB_CoverageFormat2*)cf1;
610 count = GET_BE_WORD(cf2->RangeCount);
611 TRACE("Coverage Format 2, %i ranges\n",count);
612 for (i = 0; i < count; i++)
614 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
615 return -1;
616 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
617 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
619 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
620 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
623 return -1;
625 else
626 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
628 return -1;
631 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
633 const GSUB_ScriptList *script;
634 const GSUB_Script *deflt = NULL;
635 int i;
636 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
638 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
639 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
641 const GSUB_Script *scr;
642 int offset;
644 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
645 scr = (const GSUB_Script*)((const BYTE*)script + offset);
647 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
648 return scr;
649 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
650 deflt = scr;
652 return deflt;
655 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
657 int i;
658 int offset;
659 const GSUB_LangSys *Lang;
661 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
663 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
665 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
666 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
668 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
669 return Lang;
671 offset = GET_BE_WORD(script->DefaultLangSys);
672 if (offset)
674 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
675 return Lang;
677 return NULL;
680 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
682 int i;
683 const GSUB_FeatureList *feature;
684 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
686 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
687 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
689 int index = GET_BE_WORD(lang->FeatureIndex[i]);
690 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
692 const GSUB_Feature *feat;
693 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
694 return feat;
697 return NULL;
700 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
702 int j;
703 TRACE("Single Substitution Subtable\n");
705 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
707 int offset;
708 const GSUB_SingleSubstFormat1 *ssf1;
709 offset = GET_BE_WORD(look->SubTable[j]);
710 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
711 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
713 int offset = GET_BE_WORD(ssf1->Coverage);
714 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
715 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
717 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
718 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
719 TRACE(" 0x%x\n",glyphs[glyph_index]);
720 return glyph_index + 1;
723 else
725 const GSUB_SingleSubstFormat2 *ssf2;
726 INT index;
727 INT offset;
729 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
730 offset = GET_BE_WORD(ssf1->Coverage);
731 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
732 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
733 TRACE(" Coverage index %i\n",index);
734 if (index != -1)
736 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
737 return GSUB_E_NOGLYPH;
739 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
740 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
741 TRACE("0x%x\n",glyphs[glyph_index]);
742 return glyph_index + 1;
746 return GSUB_E_NOGLYPH;
749 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
751 int j;
752 TRACE("Multiple Substitution Subtable\n");
754 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
756 int offset, index;
757 const GSUB_MultipleSubstFormat1 *msf1;
758 offset = GET_BE_WORD(look->SubTable[j]);
759 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
761 offset = GET_BE_WORD(msf1->Coverage);
762 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
763 if (index != -1)
765 const GSUB_Sequence *seq;
766 int sub_count;
767 int j;
768 offset = GET_BE_WORD(msf1->Sequence[index]);
769 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
770 sub_count = GET_BE_WORD(seq->GlyphCount);
771 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
773 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
774 glyphs[j] =glyphs[j-(sub_count-1)];
776 for (j = 0; j < sub_count; j++)
777 if (write_dir < 0)
778 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
779 else
780 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
782 *glyph_count = *glyph_count + (sub_count - 1);
784 if (TRACE_ON(uniscribe))
786 for (j = 0; j < sub_count; j++)
787 TRACE(" 0x%x",glyphs[glyph_index+j]);
788 TRACE("\n");
791 return glyph_index + sub_count;
794 return GSUB_E_NOGLYPH;
797 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
799 int j;
800 TRACE("Alternate Substitution Subtable\n");
802 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
804 int offset;
805 const GSUB_AlternateSubstFormat1 *asf1;
806 INT index;
808 offset = GET_BE_WORD(look->SubTable[j]);
809 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
810 offset = GET_BE_WORD(asf1->Coverage);
812 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
813 if (index != -1)
815 const GSUB_AlternateSet *as;
816 offset = GET_BE_WORD(asf1->AlternateSet[index]);
817 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
818 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
819 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
820 return GSUB_E_NOGLYPH;
822 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
823 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
824 TRACE(" 0x%x\n",glyphs[glyph_index]);
825 return glyph_index + 1;
828 return GSUB_E_NOGLYPH;
831 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
833 int j;
835 TRACE("Ligature Substitution Subtable\n");
836 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
838 const GSUB_LigatureSubstFormat1 *lsf1;
839 int offset,index;
841 offset = GET_BE_WORD(look->SubTable[j]);
842 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
843 offset = GET_BE_WORD(lsf1->Coverage);
844 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
845 TRACE(" Coverage index %i\n",index);
846 if (index != -1)
848 const GSUB_LigatureSet *ls;
849 int k, count;
851 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
852 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
853 count = GET_BE_WORD(ls->LigatureCount);
854 TRACE(" LigatureSet has %i members\n",count);
855 for (k = 0; k < count; k++)
857 const GSUB_Ligature *lig;
858 int CompCount,l,CompIndex;
860 offset = GET_BE_WORD(ls->Ligature[k]);
861 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
862 CompCount = GET_BE_WORD(lig->CompCount) - 1;
863 CompIndex = glyph_index+write_dir;
864 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
866 int CompGlyph;
867 CompGlyph = GET_BE_WORD(lig->Component[l]);
868 if (CompGlyph != glyphs[CompIndex])
869 break;
870 CompIndex += write_dir;
872 if (l == CompCount)
874 int replaceIdx = glyph_index;
875 if (write_dir < 0)
876 replaceIdx = glyph_index - CompCount;
878 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
879 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
880 TRACE("0x%x\n",glyphs[replaceIdx]);
881 if (CompCount > 0)
883 int j;
884 for (j = replaceIdx + 1; j < *glyph_count; j++)
885 glyphs[j] =glyphs[j+CompCount];
886 *glyph_count = *glyph_count - CompCount;
888 return replaceIdx + 1;
893 return GSUB_E_NOGLYPH;
896 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
898 int j;
899 BOOL done = FALSE;
901 TRACE("Chaining Contextual Substitution Subtable\n");
902 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
904 const GSUB_ChainContextSubstFormat1 *ccsf1;
905 int offset;
906 int dirLookahead = write_dir;
907 int dirBacktrack = -1 * write_dir;
909 offset = GET_BE_WORD(look->SubTable[j]);
910 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
911 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
913 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
914 continue;
916 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
918 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
919 continue;
921 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
923 int k;
924 int indexGlyphs;
925 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
926 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
927 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
928 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
929 int newIndex = glyph_index;
931 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
933 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
935 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
937 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
938 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
939 break;
941 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
942 continue;
943 TRACE("Matched Backtrack\n");
945 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
947 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
948 for (k = 0; k < indexGlyphs; k++)
950 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
951 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
952 break;
954 if (k != indexGlyphs)
955 continue;
956 TRACE("Matched IndexGlyphs\n");
958 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
960 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
962 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
963 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
964 break;
966 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
967 continue;
968 TRACE("Matched LookAhead\n");
970 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
972 if (GET_BE_WORD(ccsf3_4->SubstCount))
974 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
976 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
977 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
979 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
980 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
981 if (newIndex == -1)
983 ERR("Chain failed to generate a glyph\n");
984 continue;
987 return newIndex;
989 else return GSUB_E_NOGLYPH;
992 return -1;
995 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
997 int offset;
998 const GSUB_LookupTable *look;
1000 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1001 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1002 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1003 switch(GET_BE_WORD(look->LookupType))
1005 case 1:
1006 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1007 case 2:
1008 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1009 case 3:
1010 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1011 case 4:
1012 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1013 case 6:
1014 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1015 default:
1016 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1018 return GSUB_E_NOGLYPH;
1021 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1023 int i;
1024 int out_index = GSUB_E_NOGLYPH;
1025 const GSUB_LookupList *lookup;
1027 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1029 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1030 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1032 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1033 if (out_index != GSUB_E_NOGLYPH)
1034 break;
1036 if (out_index == GSUB_E_NOGLYPH)
1037 TRACE("lookups found no glyphs\n");
1038 else
1040 int out2;
1041 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1042 if (out2!=GSUB_E_NOGLYPH)
1043 out_index = out2;
1045 return out_index;
1048 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1050 UINT charset;
1052 if (psc->userScript != 0)
1054 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1055 return ShapingData[psa->eScript].newOtTag;
1056 else
1057 return (char*)&psc->userScript;
1060 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1061 return ShapingData[psa->eScript].newOtTag;
1063 if (ShapingData[psa->eScript].otTag[0] != 0)
1064 return ShapingData[psa->eScript].otTag;
1067 * fall back to the font charset
1069 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1070 switch (charset)
1072 case ANSI_CHARSET: return "latn";
1073 case BALTIC_CHARSET: return "latn"; /* ?? */
1074 case CHINESEBIG5_CHARSET: return "hani";
1075 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1076 case GB2312_CHARSET: return "hani";
1077 case GREEK_CHARSET: return "grek";
1078 case HANGUL_CHARSET: return "hang";
1079 case RUSSIAN_CHARSET: return "cyrl";
1080 case SHIFTJIS_CHARSET: return "kana";
1081 case TURKISH_CHARSET: return "latn"; /* ?? */
1082 case VIETNAMESE_CHARSET: return "latn";
1083 case JOHAB_CHARSET: return "latn"; /* ?? */
1084 case ARABIC_CHARSET: return "arab";
1085 case HEBREW_CHARSET: return "hebr";
1086 case THAI_CHARSET: return "thai";
1087 default: return "latn";
1091 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1093 const GSUB_Feature *feature;
1094 int i;
1096 for (i = 0; i < psc->feature_count; i++)
1097 if (strncmp(psc->features[i].tag,feat,4)==0)
1098 return psc->features[i].feature;
1100 feature = NULL;
1102 if (psc->GSUB_Table)
1104 const GSUB_Script *script;
1105 const GSUB_LangSys *language;
1106 int attempt = 2;
1110 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1111 attempt--;
1112 if (script)
1114 if (psc->userLang != 0)
1115 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1116 else
1117 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1118 if (language)
1119 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1121 } while(attempt && !feature);
1123 /* try in the default (latin) table */
1124 if (!feature)
1126 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1127 if (script)
1129 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1130 if (language)
1131 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1136 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1138 psc->feature_count++;
1140 if (psc->features)
1141 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1142 else
1143 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1145 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1146 psc->features[psc->feature_count - 1].feature = feature;
1147 return feature;
1150 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)
1152 const GSUB_Feature *feature;
1154 feature = load_GSUB_feature(hdc, psa, psc, feat);
1155 if (!feature)
1156 return GSUB_E_NOFEATURE;
1158 TRACE("applying feature %s\n",feat);
1159 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1162 static VOID *load_gsub_table(HDC hdc)
1164 VOID* GSUB_Table = NULL;
1165 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1166 if (length != GDI_ERROR)
1168 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1169 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1170 TRACE("Loaded GSUB table of %i bytes\n",length);
1172 return GSUB_Table;
1175 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)
1177 WORD *glyphs;
1178 INT glyph_count = count;
1179 INT rc;
1181 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1182 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1183 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1184 if (rc > GSUB_E_NOGLYPH)
1185 rc = count - glyph_count;
1186 else
1187 rc = 0;
1189 HeapFree(GetProcessHeap(),0,glyphs);
1190 return rc;
1193 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1195 int offset;
1196 WORD class = 0;
1197 const GDEF_ClassDefFormat1 *cf1;
1199 if (!header)
1200 return 0;
1202 offset = GET_BE_WORD(header->GlyphClassDef);
1203 if (!offset)
1204 return 0;
1206 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1207 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1209 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1211 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1212 if (index < GET_BE_WORD(cf1->GlyphCount))
1213 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1216 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1218 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1219 int i, top;
1220 top = GET_BE_WORD(cf2->ClassRangeCount);
1221 for (i = 0; i < top; i++)
1223 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1224 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1226 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1227 break;
1231 else
1232 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1234 return class;
1237 static VOID *load_gdef_table(HDC hdc)
1239 VOID* GDEF_Table = NULL;
1240 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1241 if (length != GDI_ERROR)
1243 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1244 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1245 TRACE("Loaded GDEF table of %i bytes\n",length);
1247 return GDEF_Table;
1250 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1252 int i;
1254 if (!psc->GDEF_Table)
1255 psc->GDEF_Table = load_gdef_table(hdc);
1257 for (i = 0; i < cGlyphs; i++)
1259 WORD class;
1261 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1263 switch (class)
1265 case 0:
1266 case BaseGlyph:
1267 pGlyphProp[i].sva.fClusterStart = 1;
1268 pGlyphProp[i].sva.fDiacritic = 0;
1269 pGlyphProp[i].sva.fZeroWidth = 0;
1270 break;
1271 case LigatureGlyph:
1272 pGlyphProp[i].sva.fClusterStart = 1;
1273 pGlyphProp[i].sva.fDiacritic = 0;
1274 pGlyphProp[i].sva.fZeroWidth = 0;
1275 break;
1276 case MarkGlyph:
1277 pGlyphProp[i].sva.fClusterStart = 0;
1278 pGlyphProp[i].sva.fDiacritic = 1;
1279 pGlyphProp[i].sva.fZeroWidth = 1;
1280 break;
1281 case ComponentGlyph:
1282 pGlyphProp[i].sva.fClusterStart = 0;
1283 pGlyphProp[i].sva.fDiacritic = 0;
1284 pGlyphProp[i].sva.fZeroWidth = 0;
1285 break;
1286 default:
1287 ERR("Unknown glyph class %i\n",class);
1288 pGlyphProp[i].sva.fClusterStart = 1;
1289 pGlyphProp[i].sva.fDiacritic = 0;
1290 pGlyphProp[i].sva.fZeroWidth = 0;
1295 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1297 int i;
1299 for (i = 0; i < cGlyphs; i++)
1301 if (!pGlyphProp[i].sva.fClusterStart)
1303 int j;
1304 for (j = 0; j < cChars; j++)
1306 if (pwLogClust[j] == i)
1308 int k = j;
1309 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1310 k-=1;
1311 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1312 pwLogClust[j] = pwLogClust[k];
1319 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1321 if (changeCount == 0)
1322 return;
1323 else
1325 int i;
1326 int target_glyph = nextIndex - 1;
1327 int seeking_glyph;
1328 int target_index = -1;
1329 int replacing_glyph = -1;
1330 int changed = 0;
1333 if (changeCount > 0)
1334 target_glyph = nextIndex - (changeCount+1);
1336 seeking_glyph = target_glyph;
1338 do {
1339 if (write_dir > 0)
1340 for (i = 0; i < chars; i++)
1342 if (pwLogClust[i] == seeking_glyph)
1344 target_index = i;
1345 break;
1348 else
1349 for (i = chars - 1; i >= 0; i--)
1351 if (pwLogClust[i] == seeking_glyph)
1353 target_index = i;
1354 break;
1357 if (target_index == -1)
1358 seeking_glyph ++;
1360 while (target_index == -1 && seeking_glyph < chars);
1362 if (target_index == -1)
1364 ERR("Unable to find target glyph\n");
1365 return;
1368 if (changeCount < 0)
1370 /* merge glyphs */
1371 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1373 if (pwLogClust[i] == target_glyph)
1374 continue;
1375 if(pwLogClust[i] == replacing_glyph)
1376 pwLogClust[i] = target_glyph;
1377 else
1379 changed--;
1380 if (changed >= changeCount)
1382 replacing_glyph = pwLogClust[i];
1383 pwLogClust[i] = target_glyph;
1385 else
1386 break;
1390 /* renumber trailing indexes*/
1391 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1393 if (pwLogClust[i] != target_glyph)
1394 pwLogClust[i] += changeCount;
1397 else
1399 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1400 pwLogClust[i] += changeCount;
1405 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 )
1407 int i;
1409 if (psc->GSUB_Table)
1411 const GSUB_Feature *feature;
1413 feature = load_GSUB_feature(hdc, psa, psc, feat);
1414 if (!feature)
1415 return GSUB_E_NOFEATURE;
1417 i = 0;
1418 TRACE("applying feature %s\n",debugstr_an(feat,4));
1419 while(i < *pcGlyphs)
1421 INT nextIndex;
1422 INT prevCount = *pcGlyphs;
1423 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1424 if (nextIndex > GSUB_E_NOGLYPH)
1426 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1427 i = nextIndex;
1429 else
1430 i++;
1432 return *pcGlyphs;
1434 return GSUB_E_NOFEATURE;
1437 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1439 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1442 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1444 if (i + delta < 0)
1445 return 0;
1446 if ( i+ delta >= cchLen)
1447 return 0;
1449 i += delta;
1451 return chars[i];
1454 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1456 if (i + delta < 0)
1458 if (psa->fLinkBefore)
1459 return jtR;
1460 else
1461 return jtU;
1463 if ( i+ delta >= cchLen)
1465 if (psa->fLinkAfter)
1466 return jtL;
1467 else
1468 return jtU;
1471 i += delta;
1473 if (context_type[i] == jtT)
1474 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1475 else
1476 return context_type[i];
1479 static inline BOOL right_join_causing(CHAR joining_type)
1481 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1484 static inline BOOL left_join_causing(CHAR joining_type)
1486 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1489 static inline BOOL word_break_causing(WCHAR chr)
1491 /* we are working within a string of characters already guareented to
1492 be within one script, Syriac, so we do not worry about any character
1493 other than the space character outside of that range */
1494 return (chr == 0 || chr == 0x20 );
1498 * ContextualShape_Arabic
1500 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1502 CHAR *context_type;
1503 INT *context_shape;
1504 INT dirR, dirL;
1505 int i;
1507 if (*pcGlyphs != cChars)
1509 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1510 return;
1513 if (!psa->fLogicalOrder && psa->fRTL)
1515 dirR = 1;
1516 dirL = -1;
1518 else
1520 dirR = -1;
1521 dirL = 1;
1524 if (!psc->GSUB_Table)
1525 psc->GSUB_Table = load_gsub_table(hdc);
1527 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1528 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1530 for (i = 0; i < cChars; i++)
1531 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1533 for (i = 0; i < cChars; i++)
1535 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1536 context_shape[i] = Xr;
1537 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1538 context_shape[i] = Xl;
1539 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)))
1540 context_shape[i] = Xm;
1541 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1542 context_shape[i] = Xr;
1543 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1544 context_shape[i] = Xl;
1545 else
1546 context_shape[i] = Xn;
1549 /* Contextual Shaping */
1550 i = 0;
1551 while(i < *pcGlyphs)
1553 BOOL shaped = FALSE;
1555 if (psc->GSUB_Table)
1557 INT nextIndex;
1558 INT prevCount = *pcGlyphs;
1559 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1560 if (nextIndex > GSUB_E_NOGLYPH)
1562 i = nextIndex;
1563 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1565 shaped = (nextIndex > GSUB_E_NOGLYPH);
1568 if (!shaped)
1570 if (context_shape[i] == Xn)
1572 WORD newGlyph = pwOutGlyphs[i];
1573 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1575 /* fall back to presentation form B */
1576 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1577 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1578 pwOutGlyphs[i] = newGlyph;
1581 i++;
1585 HeapFree(GetProcessHeap(),0,context_shape);
1586 HeapFree(GetProcessHeap(),0,context_type);
1590 * ContextualShape_Syriac
1593 #define ALAPH 0x710
1594 #define DALATH 0x715
1595 #define RISH 0x72A
1597 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1599 CHAR *context_type;
1600 INT *context_shape;
1601 INT dirR, dirL;
1602 int i;
1604 if (*pcGlyphs != cChars)
1606 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1607 return;
1610 if (!psa->fLogicalOrder && psa->fRTL)
1612 dirR = 1;
1613 dirL = -1;
1615 else
1617 dirR = -1;
1618 dirL = 1;
1621 if (!psc->GSUB_Table)
1622 psc->GSUB_Table = load_gsub_table(hdc);
1624 if (!psc->GSUB_Table)
1625 return;
1627 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1628 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1630 for (i = 0; i < cChars; i++)
1631 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1633 for (i = 0; i < cChars; i++)
1635 if (pwcChars[i] == ALAPH)
1637 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1639 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1640 context_shape[i] = Afj;
1641 else if ( rchar != DALATH && rchar != RISH &&
1642 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1643 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1644 context_shape[i] = Afn;
1645 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1646 context_shape[i] = Afx;
1647 else
1648 context_shape[i] = Xn;
1650 else if (context_type[i] == jtR &&
1651 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1652 context_shape[i] = Xr;
1653 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1654 context_shape[i] = Xl;
1655 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)))
1656 context_shape[i] = Xm;
1657 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1658 context_shape[i] = Xr;
1659 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1660 context_shape[i] = Xl;
1661 else
1662 context_shape[i] = Xn;
1665 /* Contextual Shaping */
1666 i = 0;
1667 while(i < *pcGlyphs)
1669 INT nextIndex;
1670 INT prevCount = *pcGlyphs;
1671 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1672 if (nextIndex > GSUB_E_NOGLYPH)
1674 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1675 i = nextIndex;
1677 else
1678 i++;
1681 HeapFree(GetProcessHeap(),0,context_shape);
1682 HeapFree(GetProcessHeap(),0,context_type);
1686 * ContextualShape_Phags_pa
1689 #define phags_pa_CANDRABINDU 0xA873
1690 #define phags_pa_START 0xA840
1691 #define phags_pa_END 0xA87F
1693 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1695 INT *context_shape;
1696 INT dirR, dirL;
1697 int i;
1699 if (*pcGlyphs != cChars)
1701 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1702 return;
1705 if (!psa->fLogicalOrder && psa->fRTL)
1707 dirR = 1;
1708 dirL = -1;
1710 else
1712 dirR = -1;
1713 dirL = 1;
1716 if (!psc->GSUB_Table)
1717 psc->GSUB_Table = load_gsub_table(hdc);
1719 if (!psc->GSUB_Table)
1720 return;
1722 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1724 for (i = 0; i < cChars; i++)
1726 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1728 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1729 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1730 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1731 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1733 if (jrchar && jlchar)
1734 context_shape[i] = Xm;
1735 else if (jrchar)
1736 context_shape[i] = Xr;
1737 else if (jlchar)
1738 context_shape[i] = Xl;
1739 else
1740 context_shape[i] = Xn;
1742 else
1743 context_shape[i] = -1;
1746 /* Contextual Shaping */
1747 i = 0;
1748 while(i < *pcGlyphs)
1750 if (context_shape[i] >= 0)
1752 INT nextIndex;
1753 INT prevCount = *pcGlyphs;
1754 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1755 if (nextIndex > GSUB_E_NOGLYPH)
1757 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1758 i = nextIndex;
1760 else
1761 i++;
1763 else
1764 i++;
1767 HeapFree(GetProcessHeap(),0,context_shape);
1770 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1772 int i;
1774 /* Replace */
1775 pwOutChars[cWalk] = replacements[0];
1776 cWalk=cWalk+1;
1778 /* Insert */
1779 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1781 int j;
1782 for (j = *pcChars; j > cWalk; j--)
1783 pwOutChars[j] = pwOutChars[j-1];
1784 *pcChars= *pcChars+1;
1785 pwOutChars[cWalk] = replacements[i];
1786 cWalk = cWalk+1;
1790 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust)
1792 int i;
1793 int cWalk;
1794 int offset = 0;
1796 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1798 for (i = 0; vowels[i].base != 0x0; i++)
1800 if (pwOutChars[cWalk] == vowels[i].base)
1802 int j;
1803 int o = 1;
1804 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1805 if (vowels[i].parts[1]) { cWalk++; o++; }
1806 if (vowels[i].parts[2]) { cWalk++; o++; }
1807 offset += o;
1808 for (j = (cWalk - offset) + 1; j < *pcChars - offset; j ++)
1809 pwLogClust[j]+=o;
1810 break;
1816 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1818 int i;
1819 int offset = 0;
1820 int cWalk;
1822 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1824 for (i = 0; consonants[i].output!= 0x0; i++)
1826 int j;
1827 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1828 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1829 break;
1831 if (consonants[i].parts[j]==0x0) /* matched all */
1833 int k;
1834 j--;
1835 pwOutChars[cWalk] = consonants[i].output;
1836 for(k = cWalk+1; k < *pcChars - j; k++)
1837 pwOutChars[k] = pwOutChars[k+j];
1838 *pcChars = *pcChars - j;
1839 for (k = j ; k > 0; k--)
1840 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1841 offset += j;
1842 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1843 pwLogClust[k]--;
1844 break;
1847 cWalk++;
1851 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1853 if (s->ralf >= 0)
1855 int j;
1856 WORD Ra = pwChar[s->start];
1857 WORD H = pwChar[s->start+1];
1859 TRACE("Doing reorder of Ra to %i\n",s->base);
1860 for (j = s->start; j < s->base-1; j++)
1861 pwChar[j] = pwChar[j+2];
1862 pwChar[s->base-1] = Ra;
1863 pwChar[s->base] = H;
1865 s->ralf = s->base-1;
1866 s->base -= 2;
1870 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1872 if (s->ralf >= 0)
1874 int j,loc;
1875 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1876 WORD Ra = pwChar[s->start];
1877 WORD H = pwChar[s->start+1];
1878 for (loc = s->end; loc > stop; loc--)
1879 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1880 break;
1882 TRACE("Doing reorder of Ra to %i\n",loc);
1883 for (j = s->start; j < loc-1; j++)
1884 pwChar[j] = pwChar[j+2];
1885 pwChar[loc-1] = Ra;
1886 pwChar[loc] = H;
1888 s->ralf = loc-1;
1889 s->base -= 2;
1890 if (s->blwf >= 0) s->blwf -= 2;
1891 if (s->pref >= 0) s->pref -= 2;
1895 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1897 if (s->ralf >= 0)
1899 int j;
1900 WORD Ra = pwChar[s->start];
1901 WORD H = pwChar[s->start+1];
1903 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1904 for (j = s->start; j < s->end-1; j++)
1905 pwChar[j] = pwChar[j+2];
1906 pwChar[s->end-1] = Ra;
1907 pwChar[s->end] = H;
1909 s->ralf = s->end-1;
1910 s->base -= 2;
1911 if (s->blwf >= 0) s->blwf -= 2;
1912 if (s->pref >= 0) s->pref -= 2;
1916 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1918 int i;
1920 /* reorder Matras */
1921 if (s->end > s->base)
1923 for (i = 1; i <= s->end-s->base; i++)
1925 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1927 int j;
1928 WCHAR c = pwChar[s->base+i];
1929 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1930 for (j = s->base+i; j > s->base; j--)
1931 pwChar[j] = pwChar[j-1];
1932 pwChar[s->base] = c;
1934 if (s->ralf >= s->base) s->ralf++;
1935 if (s->blwf >= s->base) s->blwf++;
1936 if (s->pref >= s->base) s->pref++;
1937 s->base ++;
1943 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1945 int i;
1947 /* reorder Matras */
1948 if (s->end > s->base)
1950 for (i = 1; i <= s->end-s->base; i++)
1952 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1954 int j;
1955 WCHAR c = pwChar[s->base+i];
1956 TRACE("Doing reorder of %x to %i\n",c,s->start);
1957 for (j = s->base+i; j > s->start; j--)
1958 pwChar[j] = pwChar[j-1];
1959 pwChar[s->start] = c;
1961 if (s->ralf >= 0) s->ralf++;
1962 if (s->blwf >= 0) s->blwf++;
1963 if (s->pref >= 0) s->pref++;
1964 s->base ++;
1970 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1972 if (s->blwf >= 0 && g->blwf > g->base)
1974 int j,loc;
1975 int g_offset;
1976 for (loc = s->end; loc > s->blwf; loc--)
1977 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1978 break;
1980 g_offset = (loc - s->blwf) - 1;
1982 if (loc != s->blwf)
1984 WORD blwf = glyphs[g->blwf];
1985 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1986 /* do not care about the pwChar array anymore, just the glyphs */
1987 for (j = 0; j < g_offset; j++)
1988 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1989 glyphs[g->blwf + g_offset] = blwf;
1994 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1996 int i;
1998 /* reorder previously moved Matras to correct position*/
1999 for (i = s->start; i < s->base; i++)
2001 if (lexical(pwChar[i]) == lex_Matra_pre)
2003 int j;
2004 int g_start = g->start + i - s->start;
2005 if (g_start < g->base -1 )
2007 WCHAR og = glyphs[g_start];
2008 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2009 for (j = g_start; j < g->base-1; j++)
2010 glyphs[j] = glyphs[j+1];
2011 glyphs[g->base-1] = og;
2017 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2019 if (s->pref >= 0 && g->pref > g->base)
2021 int j;
2022 WCHAR og = glyphs[g->pref];
2023 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2024 for (j = g->pref; j > g->base; j--)
2025 glyphs[j] = glyphs[j-1];
2026 glyphs[g->base] = og;
2030 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2032 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2033 if (s->start == s->base && s->base == s->end) return;
2034 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2036 Reorder_Ra_follows_base(pwChar, s, lexical);
2037 Reorder_Matra_precede_base(pwChar, s, lexical);
2040 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2042 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2043 if (s->start == s->base && s->base == s->end) return;
2044 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2046 Reorder_Ra_follows_matra(pwChar, s, lexical);
2047 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2050 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2052 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2053 if (s->start == s->base && s->base == s->end) return;
2054 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2056 Reorder_Ra_follows_base(pwChar, s, lexical);
2057 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2060 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2062 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2063 if (s->start == s->base && s->base == s->end) return;
2064 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2066 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2067 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2070 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2072 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2073 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2074 if (s->start == s->base && s->base == s->end) return;
2075 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2077 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2080 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2082 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2083 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2084 if (s->start == s->base && s->base == s->end) return;
2085 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2087 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2088 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2092 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2094 if (shift == 0)
2095 return;
2097 if (glyph_index->start > index)
2098 glyph_index->start += shift;
2099 if (glyph_index->base > index)
2100 glyph_index->base+= shift;
2101 if (glyph_index->end > index)
2102 glyph_index->end+= shift;
2103 if (glyph_index->ralf > index)
2104 glyph_index->ralf+= shift;
2105 if (glyph_index->blwf > index)
2106 glyph_index->blwf+= shift;
2107 if (glyph_index->pref > index)
2108 glyph_index->pref+= shift;
2111 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 )
2113 int index = glyph_index->start;
2115 if (!feature)
2116 return;
2118 while(index <= glyph_index->end)
2120 INT nextIndex;
2121 INT prevCount = *pcGlyphs;
2122 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2123 if (nextIndex > GSUB_E_NOGLYPH)
2125 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2126 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2127 index = nextIndex;
2129 else
2130 index++;
2134 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2136 int i = 0;
2137 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)))))
2138 i++;
2139 if (index + i <= end-1)
2140 return index + i;
2141 else
2142 return -1;
2145 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)
2147 INT index, nextIndex;
2148 INT count,g_offset;
2150 count = syllable->base - syllable->start;
2152 g_offset = 0;
2153 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2154 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2156 INT prevCount = *pcGlyphs;
2157 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2158 if (nextIndex > GSUB_E_NOGLYPH)
2160 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2161 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2162 g_offset += (*pcGlyphs - prevCount);
2165 index+=2;
2166 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2170 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)
2172 INT nextIndex;
2173 INT prevCount = *pcGlyphs;
2175 if (syllable->ralf >= 0)
2177 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2178 if (nextIndex > GSUB_E_NOGLYPH)
2180 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2181 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2186 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2188 int i = 0;
2189 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2190 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2191 is_consonant(lexical(pwChars[index+i+1])))))
2192 i++;
2193 if (index + i <= end-1)
2194 return index+i;
2195 else
2196 return -1;
2199 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)
2201 INT index, nextIndex;
2202 INT count, g_offset=0;
2203 INT ralf = syllable->ralf;
2205 count = syllable->end - syllable->base;
2207 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2209 while (index >= 0)
2211 INT prevCount = *pcGlyphs;
2212 if (ralf >=0 && ralf < index)
2214 g_offset--;
2215 ralf = -1;
2218 if (!modern)
2220 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2221 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2222 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2225 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2226 if (nextIndex > GSUB_E_NOGLYPH)
2228 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2229 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2230 g_offset += (*pcGlyphs - prevCount);
2232 else if (!modern)
2234 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2235 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2236 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2239 index+=2;
2240 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2244 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)
2246 int c;
2247 int overall_shift = 0;
2248 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2249 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2250 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2251 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2252 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2253 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2254 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2255 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2256 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2257 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2258 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2259 IndicSyllable glyph_indexs;
2261 for (c = 0; c < syllable_count; c++)
2263 int old_end;
2264 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2265 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2266 old_end = glyph_indexs.end;
2268 if (locl)
2270 TRACE("applying feature locl\n");
2271 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2273 if (nukt)
2275 TRACE("applying feature nukt\n");
2276 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2278 if (akhn)
2280 TRACE("applying feature akhn\n");
2281 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2284 if (rphf)
2285 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2286 if (rkrf)
2288 TRACE("applying feature rkrf\n");
2289 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2291 if (pref)
2292 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2293 if (blwf)
2295 if (!modern)
2296 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2298 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2301 if (half)
2302 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2303 if (pstf)
2305 TRACE("applying feature pstf\n");
2306 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2308 if (vatu)
2310 TRACE("applying feature vatu\n");
2311 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2313 if (cjct)
2315 TRACE("applying feature cjct\n");
2316 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2319 if (second_reorder)
2320 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2322 overall_shift += glyph_indexs.end - old_end;
2326 static inline int unicode_lex(WCHAR c)
2328 int type;
2330 if (!c) return lex_Generic;
2331 if (c == 0x200D) return lex_ZWJ;
2332 if (c == 0x200C) return lex_ZWNJ;
2333 if (c == 0x00A0) return lex_NBSP;
2335 type = get_table_entry( indic_syllabic_table, c );
2337 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2339 switch( type )
2341 case 0x0d07: /* Unknown */
2342 case 0x0e07: /* Unknwon */
2343 default: return lex_Generic;
2344 case 0x0001:
2345 case 0x0002:
2346 case 0x0011:
2347 case 0x0012:
2348 case 0x0013:
2349 case 0x0014: return lex_Modifier;
2350 case 0x0003:
2351 case 0x0009:
2352 case 0x000a:
2353 case 0x000b:
2354 case 0x000d:
2355 case 0x000e:
2356 case 0x000f:
2357 case 0x0010: return lex_Consonant;
2358 case 0x0004: return lex_Nukta;
2359 case 0x0005: return lex_Halant;
2360 case 0x0006:
2361 case 0x0008: return lex_Vowel;
2362 case 0x0007:
2363 case 0x0107: return lex_Matra_post;
2364 case 0x0207:
2365 case 0x0307: return lex_Matra_pre;
2366 case 0x0807:
2367 case 0x0907:
2368 case 0x0a07:
2369 case 0x0b07:
2370 case 0x0c07:
2371 case 0x0407: return lex_Composed_Vowel;
2372 case 0x0507: return lex_Matra_above;
2373 case 0x0607: return lex_Matra_below;
2374 case 0x000c: return lex_Ra;
2378 static int sinhala_lex(WCHAR c)
2380 switch (c)
2382 case 0x0DDA:
2383 case 0x0DDD:
2384 case 0x0DDC:
2385 case 0x0DDE: return lex_Matra_post;
2386 default:
2387 return unicode_lex(c);
2391 static const VowelComponents Sinhala_vowels[] = {
2392 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2393 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2394 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2395 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2396 {0x0000, {0x0000,0x0000,0x0}}};
2398 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2400 int cCount = cChars;
2401 int i;
2402 WCHAR *input;
2403 IndicSyllable *syllables = NULL;
2404 int syllable_count = 0;
2406 if (*pcGlyphs != cChars)
2408 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2409 return;
2412 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2414 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2416 /* Step 1: Decompose multi part vowels */
2417 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust);
2419 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2421 /* Step 2: Reorder within Syllables */
2422 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2423 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2425 /* Step 3: Strip dangling joiners */
2426 for (i = 0; i < cCount; i++)
2428 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2429 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2430 input[i] = 0x0020;
2433 /* Step 4: Base Form application to syllables */
2434 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2435 *pcGlyphs = cCount;
2436 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2438 HeapFree(GetProcessHeap(),0,input);
2439 HeapFree(GetProcessHeap(),0,syllables);
2442 static int devanagari_lex(WCHAR c)
2444 switch (c)
2446 case 0x0930: return lex_Ra;
2447 default:
2448 return unicode_lex(c);
2452 static const ConsonantComponents Devanagari_consonants[] ={
2453 {{0x0928, 0x093C, 0x00000}, 0x0929},
2454 {{0x0930, 0x093C, 0x00000}, 0x0931},
2455 {{0x0933, 0x093C, 0x00000}, 0x0934},
2456 {{0x0915, 0x093C, 0x00000}, 0x0958},
2457 {{0x0916, 0x093C, 0x00000}, 0x0959},
2458 {{0x0917, 0x093C, 0x00000}, 0x095A},
2459 {{0x091C, 0x093C, 0x00000}, 0x095B},
2460 {{0x0921, 0x093C, 0x00000}, 0x095C},
2461 {{0x0922, 0x093C, 0x00000}, 0x095D},
2462 {{0x092B, 0x093C, 0x00000}, 0x095E},
2463 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2465 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2467 int cCount = cChars;
2468 WCHAR *input;
2469 IndicSyllable *syllables = NULL;
2470 int syllable_count = 0;
2471 BOOL modern = get_GSUB_Indic2(psa, psc);
2473 if (*pcGlyphs != cChars)
2475 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2476 return;
2479 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2480 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2482 /* Step 1: Compose Consonant and Nukta */
2483 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2484 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2486 /* Step 2: Reorder within Syllables */
2487 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2488 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2489 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2490 *pcGlyphs = cCount;
2492 /* Step 3: Base Form application to syllables */
2493 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2495 HeapFree(GetProcessHeap(),0,input);
2496 HeapFree(GetProcessHeap(),0,syllables);
2499 static int bengali_lex(WCHAR c)
2501 switch (c)
2503 case 0x09B0: return lex_Ra;
2504 default:
2505 return unicode_lex(c);
2509 static const VowelComponents Bengali_vowels[] = {
2510 {0x09CB, {0x09C7,0x09BE,0x0000}},
2511 {0x09CC, {0x09C7,0x09D7,0x0000}},
2512 {0x0000, {0x0000,0x0000,0x0000}}};
2514 static const ConsonantComponents Bengali_consonants[] = {
2515 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2516 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2517 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2518 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2519 {{0x0000,0x0000,0x0000}, 0x0000}};
2521 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2523 int cCount = cChars;
2524 WCHAR *input;
2525 IndicSyllable *syllables = NULL;
2526 int syllable_count = 0;
2527 BOOL modern = get_GSUB_Indic2(psa, psc);
2529 if (*pcGlyphs != cChars)
2531 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2532 return;
2535 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2536 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2538 /* Step 1: Decompose Vowels and Compose Consonents */
2539 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust);
2540 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2541 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2543 /* Step 2: Reorder within Syllables */
2544 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2545 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2546 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2547 *pcGlyphs = cCount;
2549 /* Step 3: Initial form is only applied to the beginning of words */
2550 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2552 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2554 int index = cCount;
2555 int gCount = 1;
2556 if (index > 0) index++;
2558 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2562 /* Step 4: Base Form application to syllables */
2563 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2565 HeapFree(GetProcessHeap(),0,input);
2566 HeapFree(GetProcessHeap(),0,syllables);
2569 static int gurmukhi_lex(WCHAR c)
2571 return unicode_lex(c);
2574 static const ConsonantComponents Gurmukhi_consonants[] = {
2575 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2576 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2577 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2578 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2579 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2580 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2581 {{0x0000,0x0000,0x0000}, 0x0000}};
2583 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2585 int cCount = cChars;
2586 WCHAR *input;
2587 IndicSyllable *syllables = NULL;
2588 int syllable_count = 0;
2589 BOOL modern = get_GSUB_Indic2(psa, psc);
2591 if (*pcGlyphs != cChars)
2593 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2594 return;
2597 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2598 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2600 /* Step 1: Compose Consonents */
2601 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2602 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2604 /* Step 2: Reorder within Syllables */
2605 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2606 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2607 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2608 *pcGlyphs = cCount;
2610 /* Step 3: Base Form application to syllables */
2611 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2613 HeapFree(GetProcessHeap(),0,input);
2614 HeapFree(GetProcessHeap(),0,syllables);
2617 static int gujarati_lex(WCHAR c)
2619 switch (c)
2621 case 0x0AB0: return lex_Ra;
2622 default:
2623 return unicode_lex(c);
2627 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2629 int cCount = cChars;
2630 WCHAR *input;
2631 IndicSyllable *syllables = NULL;
2632 int syllable_count = 0;
2633 BOOL modern = get_GSUB_Indic2(psa, psc);
2635 if (*pcGlyphs != cChars)
2637 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2638 return;
2641 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2642 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2644 /* Step 1: Reorder within Syllables */
2645 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2646 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2647 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2648 *pcGlyphs = cCount;
2650 /* Step 2: Base Form application to syllables */
2651 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2653 HeapFree(GetProcessHeap(),0,input);
2654 HeapFree(GetProcessHeap(),0,syllables);
2657 static int oriya_lex(WCHAR c)
2659 switch (c)
2661 case 0x0B30: return lex_Ra;
2662 default:
2663 return unicode_lex(c);
2667 static const VowelComponents Oriya_vowels[] = {
2668 {0x0B48, {0x0B47,0x0B56,0x0000}},
2669 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2670 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2671 {0x0000, {0x0000,0x0000,0x0000}}};
2673 static const ConsonantComponents Oriya_consonants[] = {
2674 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2675 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2676 {{0x0000,0x0000,0x0000}, 0x0000}};
2678 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2680 int cCount = cChars;
2681 WCHAR *input;
2682 IndicSyllable *syllables = NULL;
2683 int syllable_count = 0;
2684 BOOL modern = get_GSUB_Indic2(psa, psc);
2686 if (*pcGlyphs != cChars)
2688 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2689 return;
2692 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2693 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2695 /* Step 1: Decompose Vowels and Compose Consonents */
2696 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust);
2697 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2698 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2700 /* Step 2: Reorder within Syllables */
2701 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2702 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2703 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2704 *pcGlyphs = cCount;
2706 /* Step 3: Base Form application to syllables */
2707 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2709 HeapFree(GetProcessHeap(),0,input);
2710 HeapFree(GetProcessHeap(),0,syllables);
2713 static int tamil_lex(WCHAR c)
2715 return unicode_lex(c);
2718 static const VowelComponents Tamil_vowels[] = {
2719 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2720 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2721 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2722 {0x0000, {0x0000,0x0000,0x0000}}};
2724 static const ConsonantComponents Tamil_consonants[] = {
2725 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2726 {{0x0000,0x0000,0x0000}, 0x0000}};
2728 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2730 int cCount = cChars;
2731 WCHAR *input;
2732 IndicSyllable *syllables = NULL;
2733 int syllable_count = 0;
2734 BOOL modern = get_GSUB_Indic2(psa, psc);
2736 if (*pcGlyphs != cChars)
2738 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2739 return;
2742 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2743 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2745 /* Step 1: Decompose Vowels and Compose Consonents */
2746 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust);
2747 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2748 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2750 /* Step 2: Reorder within Syllables */
2751 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2752 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2753 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2754 *pcGlyphs = cCount;
2756 /* Step 3: Base Form application to syllables */
2757 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2759 HeapFree(GetProcessHeap(),0,input);
2760 HeapFree(GetProcessHeap(),0,syllables);
2763 static int telugu_lex(WCHAR c)
2765 switch (c)
2767 case 0x0C43:
2768 case 0x0C44: return lex_Modifier;
2769 default:
2770 return unicode_lex(c);
2774 static const VowelComponents Telugu_vowels[] = {
2775 {0x0C48, {0x0C46,0x0C56,0x0000}},
2776 {0x0000, {0x0000,0x0000,0x0000}}};
2778 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2780 int cCount = cChars;
2781 WCHAR *input;
2782 IndicSyllable *syllables = NULL;
2783 int syllable_count = 0;
2784 BOOL modern = get_GSUB_Indic2(psa, psc);
2786 if (*pcGlyphs != cChars)
2788 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2789 return;
2792 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2793 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2795 /* Step 1: Decompose Vowels */
2796 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust);
2797 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2799 /* Step 2: Reorder within Syllables */
2800 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2801 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2802 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2803 *pcGlyphs = cCount;
2805 /* Step 3: Base Form application to syllables */
2806 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2808 HeapFree(GetProcessHeap(),0,input);
2809 HeapFree(GetProcessHeap(),0,syllables);
2812 static int kannada_lex(WCHAR c)
2814 switch (c)
2816 case 0x0CB0: return lex_Ra;
2817 default:
2818 return unicode_lex(c);
2822 static const VowelComponents Kannada_vowels[] = {
2823 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2824 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2825 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2826 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2827 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2828 {0x0000, {0x0000,0x0000,0x0000}}};
2830 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2832 int cCount = cChars;
2833 WCHAR *input;
2834 IndicSyllable *syllables = NULL;
2835 int syllable_count = 0;
2836 BOOL modern = get_GSUB_Indic2(psa, psc);
2838 if (*pcGlyphs != cChars)
2840 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2841 return;
2844 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2845 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2847 /* Step 1: Decompose Vowels */
2848 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust);
2849 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2851 /* Step 2: Reorder within Syllables */
2852 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2853 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2854 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2855 *pcGlyphs = cCount;
2857 /* Step 3: Base Form application to syllables */
2858 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2860 HeapFree(GetProcessHeap(),0,input);
2861 HeapFree(GetProcessHeap(),0,syllables);
2864 static int malayalam_lex(WCHAR c)
2866 return unicode_lex(c);
2869 static const VowelComponents Malayalam_vowels[] = {
2870 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2871 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2872 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2873 {0x0000, {0x0000,0x0000,0x0000}}};
2875 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2877 int cCount = cChars;
2878 WCHAR *input;
2879 IndicSyllable *syllables = NULL;
2880 int syllable_count = 0;
2881 BOOL modern = get_GSUB_Indic2(psa, psc);
2883 if (*pcGlyphs != cChars)
2885 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2886 return;
2889 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2890 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2892 /* Step 1: Decompose Vowels */
2893 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust);
2894 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2896 /* Step 2: Reorder within Syllables */
2897 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2898 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2899 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2900 *pcGlyphs = cCount;
2902 /* Step 3: Base Form application to syllables */
2903 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2905 HeapFree(GetProcessHeap(),0,input);
2906 HeapFree(GetProcessHeap(),0,syllables);
2909 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)
2911 int i,k;
2913 for (i = 0; i < cGlyphs; i++)
2915 int char_index[20];
2916 int char_count = 0;
2918 for (k = 0; k < cChars; k++)
2920 if (pwLogClust[k] == i)
2922 char_index[char_count] = k;
2923 char_count++;
2927 if (char_count == 0)
2929 FIXME("No chars in this glyph? Must be an error\n");
2930 continue;
2933 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2935 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2936 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2938 else
2939 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2942 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2943 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2946 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 )
2948 int i,k;
2949 int initGlyph, finaGlyph;
2950 INT dirR, dirL;
2951 BYTE *spaces;
2953 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2954 memset(spaces,0,cGlyphs);
2956 if (!psa->fLogicalOrder && psa->fRTL)
2958 initGlyph = cGlyphs-1;
2959 finaGlyph = 0;
2960 dirR = 1;
2961 dirL = -1;
2963 else
2965 initGlyph = 0;
2966 finaGlyph = cGlyphs-1;
2967 dirR = -1;
2968 dirL = 1;
2971 for (i = 0; i < cGlyphs; i++)
2973 for (k = 0; k < cChars; k++)
2974 if (pwLogClust[k] == i)
2976 if (pwcChars[k] == 0x0020)
2977 spaces[i] = 1;
2981 for (i = 0; i < cGlyphs; i++)
2983 int char_index[20];
2984 int char_count = 0;
2985 BOOL isInit, isFinal;
2987 for (k = 0; k < cChars; k++)
2989 if (pwLogClust[k] == i)
2991 char_index[char_count] = k;
2992 char_count++;
2996 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2997 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2999 if (char_count == 0)
3001 FIXME("No chars in this glyph? Must be an error\n");
3002 continue;
3005 if (char_count == 1)
3007 if (pwcChars[char_index[0]] == 0x0020) /* space */
3009 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3010 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3012 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3013 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3014 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3016 if (!isInit && !isFinal)
3017 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3018 else if (isInit)
3019 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3020 else
3021 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3023 else if (!isInit)
3025 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3026 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3027 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3028 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3029 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3030 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3031 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3032 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3033 else
3034 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3036 else if (!isInit && !isFinal)
3037 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3038 else
3039 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3041 else if (char_count == 2)
3043 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3044 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3045 else if (!isInit)
3046 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3047 else
3048 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3050 else if (!isInit && !isFinal)
3051 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3052 else
3053 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3056 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3057 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3058 HeapFree(GetProcessHeap(),0,spaces);
3061 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 )
3063 int i,k;
3064 int finaGlyph;
3065 INT dirL;
3066 BYTE *spaces;
3068 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3069 memset(spaces,0,cGlyphs);
3071 if (!psa->fLogicalOrder && psa->fRTL)
3073 finaGlyph = 0;
3074 dirL = -1;
3076 else
3078 finaGlyph = cGlyphs-1;
3079 dirL = 1;
3082 for (i = 0; i < cGlyphs; i++)
3084 for (k = 0; k < cChars; k++)
3085 if (pwLogClust[k] == i)
3087 if (pwcChars[k] == 0x0020)
3088 spaces[i] = 1;
3092 for (i = 0; i < cGlyphs; i++)
3094 int char_index[20];
3095 int char_count = 0;
3097 for (k = 0; k < cChars; k++)
3099 if (pwLogClust[k] == i)
3101 char_index[char_count] = k;
3102 char_count++;
3106 if (char_count == 0)
3108 FIXME("No chars in this glyph? Must be an error\n");
3109 continue;
3112 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3114 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3115 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3117 else if (i == finaGlyph)
3118 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3119 else
3120 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3123 HeapFree(GetProcessHeap(),0,spaces);
3124 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3125 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3127 /* Do not allow justification between marks and their base */
3128 for (i = 0; i < cGlyphs; i++)
3130 if (!pGlyphProp[i].sva.fClusterStart)
3131 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3135 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)
3137 int i,k;
3139 for (i = 0; i < cGlyphs; i++)
3141 int char_index[20];
3142 int char_count = 0;
3144 for (k = 0; k < cChars; k++)
3146 if (pwLogClust[k] == i)
3148 char_index[char_count] = k;
3149 char_count++;
3153 if (char_count == 0)
3155 FIXME("No chars in this glyph? Must be an error\n");
3156 continue;
3159 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3161 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3162 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3164 else
3165 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3167 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3168 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3171 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)
3173 int i,k;
3175 for (i = 0; i < cGlyphs; i++)
3177 int char_index[20];
3178 int char_count = 0;
3180 for (k = 0; k < cChars; k++)
3182 if (pwLogClust[k] == i)
3184 char_index[char_count] = k;
3185 char_count++;
3189 if (char_count == 0)
3191 FIXME("No chars in this glyph? Must be an error\n");
3192 continue;
3195 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3197 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3198 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3200 else
3201 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3203 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3204 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3206 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3207 for (i = 0; i < cGlyphs; i++)
3209 if (!pGlyphProp[i].sva.fClusterStart)
3211 pGlyphProp[i].sva.fDiacritic = 0;
3212 pGlyphProp[i].sva.fZeroWidth = 0;
3217 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)
3219 int i,k;
3220 IndicSyllable *syllables = NULL;
3221 int syllable_count = 0;
3222 BOOL modern = get_GSUB_Indic2(psa, psc);
3224 for (i = 0; i < cGlyphs; i++)
3226 int char_index[20];
3227 int char_count = 0;
3229 for (k = 0; k < cChars; k++)
3231 if (pwLogClust[k] == i)
3233 char_index[char_count] = k;
3234 char_count++;
3238 if (char_count == 0)
3240 FIXME("No chars in this glyph? Must be an error\n");
3241 continue;
3244 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3246 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3247 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3249 else
3250 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3252 pGlyphProp[i].sva.fClusterStart = 0;
3253 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3254 switch (lexical(pwcChars[char_index[k]]))
3256 case lex_Matra_pre:
3257 case lex_Matra_post:
3258 case lex_Matra_above:
3259 case lex_Matra_below:
3260 case lex_Modifier:
3261 break;
3262 default:
3263 pGlyphProp[i].sva.fClusterStart = 1;
3264 break;
3268 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3270 for (i = 0; i < syllable_count; i++)
3272 int j;
3273 WORD g = pwLogClust[syllables[i].start];
3274 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3276 if (pwLogClust[j] != g)
3278 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3279 pwLogClust[j] = g;
3284 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3285 HeapFree(GetProcessHeap(), 0, syllables);
3288 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 )
3290 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex);
3293 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 )
3295 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3298 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 )
3300 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3303 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 )
3305 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3308 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 )
3310 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3313 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 )
3315 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3318 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 )
3320 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3323 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 )
3325 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3328 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 )
3330 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3333 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 )
3335 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3338 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)
3340 if (ShapingData[psa->eScript].charGlyphPropProc)
3341 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3342 else
3343 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3346 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3348 if (ShapingData[psa->eScript].contextProc)
3349 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3352 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)
3354 int i;
3355 INT dirL;
3357 if (!rpRangeProperties)
3358 return;
3360 if (!psc->GSUB_Table)
3361 psc->GSUB_Table = load_gsub_table(hdc);
3363 if (!psc->GSUB_Table)
3364 return;
3366 if (!psa->fLogicalOrder && psa->fRTL)
3367 dirL = -1;
3368 else
3369 dirL = 1;
3371 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3373 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3374 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3378 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3380 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3381 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3383 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3386 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3388 const GSUB_Feature *feature;
3389 int i;
3391 if (!ShapingData[psa->eScript].requiredFeatures)
3392 return S_OK;
3394 if (!psc->GSUB_Table)
3395 psc->GSUB_Table = load_gsub_table(hdc);
3397 /* we need to have at least one of the required features */
3398 i = 0;
3399 while (ShapingData[psa->eScript].requiredFeatures[i])
3401 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3402 if (feature)
3403 return S_OK;
3404 i++;
3407 return USP_E_SCRIPT_NOT_IN_FONT;