usp10: Add CKJ Han and Ideographic scripts.
[wine/multimedia.git] / dlls / usp10 / shape.c
blobda04361e477bbc823b961bfbff8bf9da91612530
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);
56 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
60 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);
61 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 );
62 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 );
63 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 );
64 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 );
65 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 );
66 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 );
67 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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 static void ShapeCharGlyphProp_Khmer( 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 );
77 extern const unsigned short indic_syllabic_table[];
78 extern const unsigned short wine_shaping_table[];
79 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
81 enum joining_types {
82 jtU,
83 jtT,
84 jtR,
85 jtL,
86 jtD,
87 jtC
90 enum joined_forms {
91 Xn=0,
92 Xr,
93 Xl,
94 Xm,
95 /* Syriac Alaph */
96 Afj,
97 Afn,
98 Afx
101 #ifdef WORDS_BIGENDIAN
102 #define GET_BE_WORD(x) (x)
103 #else
104 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
105 #endif
107 /* These are all structures needed for the GSUB table */
108 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
109 #define GSUB_E_NOFEATURE -2
110 #define GSUB_E_NOGLYPH -1
112 typedef struct {
113 DWORD version;
114 WORD ScriptList;
115 WORD FeatureList;
116 WORD LookupList;
117 } GSUB_Header;
119 typedef struct {
120 CHAR ScriptTag[4];
121 WORD Script;
122 } GSUB_ScriptRecord;
124 typedef struct {
125 WORD ScriptCount;
126 GSUB_ScriptRecord ScriptRecord[1];
127 } GSUB_ScriptList;
129 typedef struct {
130 CHAR LangSysTag[4];
131 WORD LangSys;
132 } GSUB_LangSysRecord;
134 typedef struct {
135 WORD DefaultLangSys;
136 WORD LangSysCount;
137 GSUB_LangSysRecord LangSysRecord[1];
138 } GSUB_Script;
140 typedef struct {
141 WORD LookupOrder; /* Reserved */
142 WORD ReqFeatureIndex;
143 WORD FeatureCount;
144 WORD FeatureIndex[1];
145 } GSUB_LangSys;
147 typedef struct {
148 CHAR FeatureTag[4];
149 WORD Feature;
150 } GSUB_FeatureRecord;
152 typedef struct {
153 WORD FeatureCount;
154 GSUB_FeatureRecord FeatureRecord[1];
155 } GSUB_FeatureList;
157 typedef struct {
158 WORD FeatureParams; /* Reserved */
159 WORD LookupCount;
160 WORD LookupListIndex[1];
161 } GSUB_Feature;
163 typedef struct {
164 WORD LookupCount;
165 WORD Lookup[1];
166 } GSUB_LookupList;
168 typedef struct {
169 WORD LookupType;
170 WORD LookupFlag;
171 WORD SubTableCount;
172 WORD SubTable[1];
173 } GSUB_LookupTable;
175 typedef struct {
176 WORD CoverageFormat;
177 WORD GlyphCount;
178 WORD GlyphArray[1];
179 } GSUB_CoverageFormat1;
181 typedef struct {
182 WORD Start;
183 WORD End;
184 WORD StartCoverageIndex;
185 } GSUB_RangeRecord;
187 typedef struct {
188 WORD CoverageFormat;
189 WORD RangeCount;
190 GSUB_RangeRecord RangeRecord[1];
191 } GSUB_CoverageFormat2;
193 typedef struct {
194 WORD SubstFormat; /* = 1 */
195 WORD Coverage;
196 WORD DeltaGlyphID;
197 } GSUB_SingleSubstFormat1;
199 typedef struct {
200 WORD SubstFormat; /* = 2 */
201 WORD Coverage;
202 WORD GlyphCount;
203 WORD Substitute[1];
204 }GSUB_SingleSubstFormat2;
206 typedef struct {
207 WORD SubstFormat; /* = 1 */
208 WORD Coverage;
209 WORD SequenceCount;
210 WORD Sequence[1];
211 }GSUB_MultipleSubstFormat1;
213 typedef struct {
214 WORD GlyphCount;
215 WORD Substitute[1];
216 }GSUB_Sequence;
218 typedef struct {
219 WORD SubstFormat; /* = 1 */
220 WORD Coverage;
221 WORD LigSetCount;
222 WORD LigatureSet[1];
223 }GSUB_LigatureSubstFormat1;
225 typedef struct {
226 WORD LigatureCount;
227 WORD Ligature[1];
228 }GSUB_LigatureSet;
230 typedef struct{
231 WORD LigGlyph;
232 WORD CompCount;
233 WORD Component[1];
234 }GSUB_Ligature;
236 typedef struct{
237 WORD SequenceIndex;
238 WORD LookupListIndex;
240 }GSUB_SubstLookupRecord;
242 typedef struct{
243 WORD SubstFormat; /* = 1 */
244 WORD Coverage;
245 WORD ChainSubRuleSetCount;
246 WORD ChainSubRuleSet[1];
247 }GSUB_ChainContextSubstFormat1;
249 typedef struct {
250 WORD SubstFormat; /* = 3 */
251 WORD BacktrackGlyphCount;
252 WORD Coverage[1];
253 }GSUB_ChainContextSubstFormat3_1;
255 typedef struct{
256 WORD InputGlyphCount;
257 WORD Coverage[1];
258 }GSUB_ChainContextSubstFormat3_2;
260 typedef struct{
261 WORD LookaheadGlyphCount;
262 WORD Coverage[1];
263 }GSUB_ChainContextSubstFormat3_3;
265 typedef struct{
266 WORD SubstCount;
267 GSUB_SubstLookupRecord SubstLookupRecord[1];
268 }GSUB_ChainContextSubstFormat3_4;
270 typedef struct {
271 WORD SubstFormat; /* = 1 */
272 WORD Coverage;
273 WORD AlternateSetCount;
274 WORD AlternateSet[1];
275 } GSUB_AlternateSubstFormat1;
277 typedef struct{
278 WORD GlyphCount;
279 WORD Alternate[1];
280 } GSUB_AlternateSet;
282 /* These are all structures needed for the GDEF table */
283 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
285 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
287 typedef struct {
288 DWORD Version;
289 WORD GlyphClassDef;
290 WORD AttachList;
291 WORD LigCaretList;
292 WORD MarkAttachClassDef;
293 } GDEF_Header;
295 typedef struct {
296 WORD ClassFormat;
297 WORD StartGlyph;
298 WORD GlyphCount;
299 WORD ClassValueArray[1];
300 } GDEF_ClassDefFormat1;
302 typedef struct {
303 WORD Start;
304 WORD End;
305 WORD Class;
306 } GDEF_ClassRangeRecord;
308 typedef struct {
309 WORD ClassFormat;
310 WORD ClassRangeCount;
311 GDEF_ClassRangeRecord ClassRangeRecord[1];
312 } GDEF_ClassDefFormat2;
314 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
316 typedef struct tagVowelComponents
318 WCHAR base;
319 WCHAR parts[3];
320 } VowelComponents;
322 typedef struct tagConsonantComponents
324 WCHAR parts[3];
325 WCHAR output;
326 } ConsonantComponents;
328 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
330 /* the orders of joined_forms and contextual_features need to line up */
331 static const char* contextual_features[] =
333 "isol",
334 "fina",
335 "init",
336 "medi",
337 /* Syriac Alaph */
338 "med2",
339 "fin2",
340 "fin3"
343 static OPENTYPE_FEATURE_RECORD standard_features[] =
345 { MS_MAKE_TAG('c','c','m','p'), 1},
346 { MS_MAKE_TAG('l','o','c','l'), 1},
349 static OPENTYPE_FEATURE_RECORD latin_features[] =
351 { MS_MAKE_TAG('l','i','g','a'), 1},
352 { MS_MAKE_TAG('c','l','i','g'), 1},
355 static OPENTYPE_FEATURE_RECORD arabic_features[] =
357 { MS_MAKE_TAG('r','l','i','g'), 1},
358 { MS_MAKE_TAG('c','a','l','t'), 1},
359 { MS_MAKE_TAG('l','i','g','a'), 1},
360 { MS_MAKE_TAG('d','l','i','g'), 1},
361 { MS_MAKE_TAG('c','s','w','h'), 1},
362 { MS_MAKE_TAG('m','s','e','t'), 1},
365 static const char* required_arabic_features[] =
367 "fina",
368 "init",
369 "medi",
370 "rlig",
371 NULL
374 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
376 { MS_MAKE_TAG('d','l','i','g'), 0},
379 static OPENTYPE_FEATURE_RECORD syriac_features[] =
381 { MS_MAKE_TAG('r','l','i','g'), 1},
382 { MS_MAKE_TAG('c','a','l','t'), 1},
383 { MS_MAKE_TAG('l','i','g','a'), 1},
384 { MS_MAKE_TAG('d','l','i','g'), 1},
387 static const char* required_syriac_features[] =
389 "fina",
390 "fin2",
391 "fin3",
392 "init",
393 "medi",
394 "med2",
395 "rlig",
396 NULL
399 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
401 /* Presentation forms */
402 { MS_MAKE_TAG('b','l','w','s'), 1},
403 { MS_MAKE_TAG('a','b','v','s'), 1},
404 { MS_MAKE_TAG('p','s','t','s'), 1},
407 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
409 { MS_MAKE_TAG('a','b','v','s'), 1},
410 { MS_MAKE_TAG('b','l','w','s'), 1},
413 static OPENTYPE_FEATURE_RECORD phags_features[] =
415 { MS_MAKE_TAG('a','b','v','s'), 1},
416 { MS_MAKE_TAG('b','l','w','s'), 1},
417 { MS_MAKE_TAG('c','a','l','t'), 1},
420 static OPENTYPE_FEATURE_RECORD thai_features[] =
422 { MS_MAKE_TAG('c','c','m','p'), 1},
425 static const char* required_lao_features[] =
427 "ccmp",
428 NULL
431 static const char* required_devanagari_features[] =
433 "nukt",
434 "akhn",
435 "rphf",
436 "blwf",
437 "half",
438 "vatu",
439 "pres",
440 "abvs",
441 "blws",
442 "psts",
443 "haln",
444 NULL
447 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
449 { MS_MAKE_TAG('p','r','e','s'), 1},
450 { MS_MAKE_TAG('a','b','v','s'), 1},
451 { MS_MAKE_TAG('b','l','w','s'), 1},
452 { MS_MAKE_TAG('p','s','t','s'), 1},
453 { MS_MAKE_TAG('h','a','l','n'), 1},
454 { MS_MAKE_TAG('c','a','l','t'), 1},
457 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
459 { MS_MAKE_TAG('l','i','g','a'), 1},
460 { MS_MAKE_TAG('c','l','i','g'), 1},
463 static const char* required_bengali_features[] =
465 "nukt",
466 "akhn",
467 "rphf",
468 "blwf",
469 "half",
470 "vatu",
471 "pstf",
472 "init",
473 "abvs",
474 "blws",
475 "psts",
476 "haln",
477 NULL
480 static const char* required_gurmukhi_features[] =
482 "nukt",
483 "akhn",
484 "rphf",
485 "blwf",
486 "half",
487 "pstf",
488 "vatu",
489 "cjct",
490 "pres",
491 "abvs",
492 "blws",
493 "psts",
494 "haln",
495 "calt",
496 NULL
499 static const char* required_oriya_features[] =
501 "nukt",
502 "akhn",
503 "rphf",
504 "blwf",
505 "pstf",
506 "cjct",
507 "pres",
508 "abvs",
509 "blws",
510 "psts",
511 "haln",
512 "calt",
513 NULL
516 static const char* required_tamil_features[] =
518 "nukt",
519 "akhn",
520 "rphf",
521 "pref",
522 "half",
523 "pres",
524 "abvs",
525 "blws",
526 "psts",
527 "haln",
528 "calt",
529 NULL
532 static const char* required_telugu_features[] =
534 "nukt",
535 "akhn",
536 "rphf",
537 "pref",
538 "half",
539 "pstf",
540 "cjct",
541 "pres",
542 "abvs",
543 "blws",
544 "psts",
545 "haln",
546 "calt",
547 NULL
550 static OPENTYPE_FEATURE_RECORD khmer_features[] =
552 { MS_MAKE_TAG('p','r','e','s'), 1},
553 { MS_MAKE_TAG('b','l','w','s'), 1},
554 { MS_MAKE_TAG('a','b','v','s'), 1},
555 { MS_MAKE_TAG('p','s','t','s'), 1},
556 { MS_MAKE_TAG('c','l','i','g'), 1},
559 static const char* required_khmer_features[] =
561 "pref",
562 "blwf",
563 "abvf",
564 "pstf",
565 "pres",
566 "blws",
567 "abvs",
568 "psts",
569 "clig",
570 NULL
573 static OPENTYPE_FEATURE_RECORD no_features[] =
574 { };
576 typedef struct ScriptShapeDataTag {
577 TEXTRANGE_PROPERTIES defaultTextRange;
578 const char** requiredFeatures;
579 CHAR otTag[5];
580 CHAR newOtTag[5];
581 ContextualShapingProc contextProc;
582 ShapeCharGlyphPropProc charGlyphPropProc;
583 } ScriptShapeData;
585 /* in order of scripts */
586 static const ScriptShapeData ShapingData[] =
588 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
589 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
590 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
591 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
592 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
593 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
594 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
595 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
596 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
597 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
598 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
599 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
600 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
601 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
602 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
603 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
604 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
605 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
606 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
607 {{ phags_features, 3}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
608 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
609 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
610 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
611 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
612 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
613 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
614 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
615 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
616 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
617 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
618 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
619 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
620 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
621 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
622 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
623 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
624 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
625 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
626 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
627 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
628 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
629 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
630 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
631 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
632 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
633 {{ latin_features, 2}, NULL, "latn" , "", NULL, NULL},
634 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
635 {{ myanmar_features, 2}, NULL, "mymr", "", NULL, NULL},
636 {{ myanmar_features, 2}, NULL, "mymr", "", NULL, NULL},
637 {{ standard_features, 2}, NULL, "tale", "", NULL, NULL},
638 {{ standard_features, 2}, NULL, "talu", "", NULL, NULL},
639 {{ standard_features, 2}, NULL, "talu", "", NULL, NULL},
640 {{ khmer_features, 5}, required_khmer_features, "khmr", "", ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
641 {{ khmer_features, 5}, required_khmer_features, "khmr", "", ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
642 {{ no_features, 0}, NULL, "hani", "", NULL, NULL},
643 {{ no_features, 0}, NULL, "hani", "", NULL, NULL},
646 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
648 const GSUB_CoverageFormat1* cf1;
650 cf1 = table;
652 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
654 int count = GET_BE_WORD(cf1->GlyphCount);
655 int i;
656 TRACE("Coverage Format 1, %i glyphs\n",count);
657 for (i = 0; i < count; i++)
658 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
659 return i;
660 return -1;
662 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
664 const GSUB_CoverageFormat2* cf2;
665 int i;
666 int count;
667 cf2 = (const GSUB_CoverageFormat2*)cf1;
669 count = GET_BE_WORD(cf2->RangeCount);
670 TRACE("Coverage Format 2, %i ranges\n",count);
671 for (i = 0; i < count; i++)
673 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
674 return -1;
675 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
676 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
678 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
679 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
682 return -1;
684 else
685 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
687 return -1;
690 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
692 const GSUB_ScriptList *script;
693 const GSUB_Script *deflt = NULL;
694 int i;
695 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
697 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
698 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
700 const GSUB_Script *scr;
701 int offset;
703 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
704 scr = (const GSUB_Script*)((const BYTE*)script + offset);
706 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
707 return scr;
708 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
709 deflt = scr;
711 return deflt;
714 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
716 int i;
717 int offset;
718 const GSUB_LangSys *Lang;
720 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
722 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
724 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
725 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
727 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
728 return Lang;
730 offset = GET_BE_WORD(script->DefaultLangSys);
731 if (offset)
733 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
734 return Lang;
736 return NULL;
739 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
741 int i;
742 const GSUB_FeatureList *feature;
743 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
745 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
746 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
748 int index = GET_BE_WORD(lang->FeatureIndex[i]);
749 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
751 const GSUB_Feature *feat;
752 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
753 return feat;
756 return NULL;
759 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
761 int j;
762 TRACE("Single Substitution Subtable\n");
764 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
766 int offset;
767 const GSUB_SingleSubstFormat1 *ssf1;
768 offset = GET_BE_WORD(look->SubTable[j]);
769 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
770 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
772 int offset = GET_BE_WORD(ssf1->Coverage);
773 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
774 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
776 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
777 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
778 TRACE(" 0x%x\n",glyphs[glyph_index]);
779 return glyph_index + write_dir;
782 else
784 const GSUB_SingleSubstFormat2 *ssf2;
785 INT index;
786 INT offset;
788 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
789 offset = GET_BE_WORD(ssf1->Coverage);
790 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
791 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
792 TRACE(" Coverage index %i\n",index);
793 if (index != -1)
795 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
796 return GSUB_E_NOGLYPH;
798 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
799 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
800 TRACE("0x%x\n",glyphs[glyph_index]);
801 return glyph_index + write_dir;
805 return GSUB_E_NOGLYPH;
808 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
810 int j;
811 TRACE("Multiple Substitution Subtable\n");
813 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
815 int offset, index;
816 const GSUB_MultipleSubstFormat1 *msf1;
817 offset = GET_BE_WORD(look->SubTable[j]);
818 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
820 offset = GET_BE_WORD(msf1->Coverage);
821 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
822 if (index != -1)
824 const GSUB_Sequence *seq;
825 int sub_count;
826 int j;
827 offset = GET_BE_WORD(msf1->Sequence[index]);
828 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
829 sub_count = GET_BE_WORD(seq->GlyphCount);
830 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
832 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
833 glyphs[j] =glyphs[j-(sub_count-1)];
835 for (j = 0; j < sub_count; j++)
836 if (write_dir < 0)
837 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
838 else
839 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
841 *glyph_count = *glyph_count + (sub_count - 1);
843 if (TRACE_ON(uniscribe))
845 for (j = 0; j < sub_count; j++)
846 TRACE(" 0x%x",glyphs[glyph_index+j]);
847 TRACE("\n");
850 return glyph_index + (sub_count * write_dir);
853 return GSUB_E_NOGLYPH;
856 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
858 int j;
859 TRACE("Alternate Substitution Subtable\n");
861 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
863 int offset;
864 const GSUB_AlternateSubstFormat1 *asf1;
865 INT index;
867 offset = GET_BE_WORD(look->SubTable[j]);
868 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
869 offset = GET_BE_WORD(asf1->Coverage);
871 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
872 if (index != -1)
874 const GSUB_AlternateSet *as;
875 offset = GET_BE_WORD(asf1->AlternateSet[index]);
876 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
877 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
878 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
879 return GSUB_E_NOGLYPH;
881 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
882 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
883 TRACE(" 0x%x\n",glyphs[glyph_index]);
884 return glyph_index + write_dir;
887 return GSUB_E_NOGLYPH;
890 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
892 int j;
894 TRACE("Ligature Substitution Subtable\n");
895 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
897 const GSUB_LigatureSubstFormat1 *lsf1;
898 int offset,index;
900 offset = GET_BE_WORD(look->SubTable[j]);
901 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
902 offset = GET_BE_WORD(lsf1->Coverage);
903 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
904 TRACE(" Coverage index %i\n",index);
905 if (index != -1)
907 const GSUB_LigatureSet *ls;
908 int k, count;
910 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
911 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
912 count = GET_BE_WORD(ls->LigatureCount);
913 TRACE(" LigatureSet has %i members\n",count);
914 for (k = 0; k < count; k++)
916 const GSUB_Ligature *lig;
917 int CompCount,l,CompIndex;
919 offset = GET_BE_WORD(ls->Ligature[k]);
920 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
921 CompCount = GET_BE_WORD(lig->CompCount) - 1;
922 CompIndex = glyph_index+write_dir;
923 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
925 int CompGlyph;
926 CompGlyph = GET_BE_WORD(lig->Component[l]);
927 if (CompGlyph != glyphs[CompIndex])
928 break;
929 CompIndex += write_dir;
931 if (l == CompCount)
933 int replaceIdx = glyph_index;
934 if (write_dir < 0)
935 replaceIdx = glyph_index - CompCount;
937 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
938 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
939 TRACE("0x%x\n",glyphs[replaceIdx]);
940 if (CompCount > 0)
942 int j;
943 for (j = replaceIdx + 1; j < *glyph_count; j++)
944 glyphs[j] =glyphs[j+CompCount];
945 *glyph_count = *glyph_count - CompCount;
947 return replaceIdx + write_dir;
952 return GSUB_E_NOGLYPH;
955 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
957 int j;
958 BOOL done = FALSE;
960 TRACE("Chaining Contextual Substitution Subtable\n");
961 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
963 const GSUB_ChainContextSubstFormat1 *ccsf1;
964 int offset;
965 int dirLookahead = write_dir;
966 int dirBacktrack = -1 * write_dir;
968 offset = GET_BE_WORD(look->SubTable[j]);
969 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
970 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
972 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
973 continue;
975 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
977 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
978 continue;
980 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
982 int k;
983 int indexGlyphs;
984 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
985 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
986 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
987 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
988 int newIndex = glyph_index;
990 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
992 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
994 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
996 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
997 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
998 break;
1000 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
1001 continue;
1002 TRACE("Matched Backtrack\n");
1004 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
1006 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
1007 for (k = 0; k < indexGlyphs; k++)
1009 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
1010 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
1011 break;
1013 if (k != indexGlyphs)
1014 continue;
1015 TRACE("Matched IndexGlyphs\n");
1017 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
1019 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
1021 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
1022 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
1023 break;
1025 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
1026 continue;
1027 TRACE("Matched LookAhead\n");
1029 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
1031 if (GET_BE_WORD(ccsf3_4->SubstCount))
1033 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
1035 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
1036 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
1038 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1039 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
1040 if (newIndex == -1)
1042 ERR("Chain failed to generate a glyph\n");
1043 continue;
1046 return newIndex;
1048 else return GSUB_E_NOGLYPH;
1051 return -1;
1054 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1056 int offset;
1057 const GSUB_LookupTable *look;
1059 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1060 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1061 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1062 switch(GET_BE_WORD(look->LookupType))
1064 case 1:
1065 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1066 case 2:
1067 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1068 case 3:
1069 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1070 case 4:
1071 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1072 case 6:
1073 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1074 default:
1075 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1077 return GSUB_E_NOGLYPH;
1080 static INT GSUB_apply_feature_all_lookups(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1082 int i;
1083 int out_index = GSUB_E_NOGLYPH;
1084 const GSUB_LookupList *lookup;
1086 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1088 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1089 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1091 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1092 if (out_index != GSUB_E_NOGLYPH)
1093 break;
1095 if (out_index == GSUB_E_NOGLYPH)
1096 TRACE("lookups found no glyphs\n");
1097 else
1099 int out2;
1100 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1101 if (out2!=GSUB_E_NOGLYPH)
1102 out_index = out2;
1104 return out_index;
1107 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1109 UINT charset;
1111 if (psc->userScript != 0)
1113 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1114 return ShapingData[psa->eScript].newOtTag;
1115 else
1116 return (char*)&psc->userScript;
1119 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1120 return ShapingData[psa->eScript].newOtTag;
1122 if (ShapingData[psa->eScript].otTag[0] != 0)
1123 return ShapingData[psa->eScript].otTag;
1126 * fall back to the font charset
1128 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1129 switch (charset)
1131 case ANSI_CHARSET: return "latn";
1132 case BALTIC_CHARSET: return "latn"; /* ?? */
1133 case CHINESEBIG5_CHARSET: return "hani";
1134 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1135 case GB2312_CHARSET: return "hani";
1136 case GREEK_CHARSET: return "grek";
1137 case HANGUL_CHARSET: return "hang";
1138 case RUSSIAN_CHARSET: return "cyrl";
1139 case SHIFTJIS_CHARSET: return "kana";
1140 case TURKISH_CHARSET: return "latn"; /* ?? */
1141 case VIETNAMESE_CHARSET: return "latn";
1142 case JOHAB_CHARSET: return "latn"; /* ?? */
1143 case ARABIC_CHARSET: return "arab";
1144 case HEBREW_CHARSET: return "hebr";
1145 case THAI_CHARSET: return "thai";
1146 default: return "latn";
1150 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1152 const GSUB_Feature *feature;
1153 const char* script;
1154 int i;
1156 script = get_opentype_script(hdc,psa,psc,FALSE);
1158 for (i = 0; i < psc->feature_count; i++)
1160 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1161 return psc->features[i].feature;
1164 feature = NULL;
1166 if (psc->GSUB_Table)
1168 const GSUB_Script *script;
1169 const GSUB_LangSys *language;
1170 int attempt = 2;
1174 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1175 attempt--;
1176 if (script)
1178 if (psc->userLang != 0)
1179 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1180 else
1181 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1182 if (language)
1183 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1185 } while(attempt && !feature);
1187 /* try in the default (latin) table */
1188 if (!feature)
1190 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1191 if (script)
1193 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1194 if (language)
1195 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1200 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1202 psc->feature_count++;
1204 if (psc->features)
1205 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1206 else
1207 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1209 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1210 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1211 psc->features[psc->feature_count - 1].feature = feature;
1212 return feature;
1215 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)
1217 const GSUB_Feature *feature;
1219 feature = load_GSUB_feature(hdc, psa, psc, feat);
1220 if (!feature)
1221 return GSUB_E_NOFEATURE;
1223 TRACE("applying feature %s\n",feat);
1224 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1227 static VOID *load_gsub_table(HDC hdc)
1229 VOID* GSUB_Table = NULL;
1230 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1231 if (length != GDI_ERROR)
1233 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1234 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1235 TRACE("Loaded GSUB table of %i bytes\n",length);
1237 return GSUB_Table;
1240 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)
1242 WORD *glyphs;
1243 INT glyph_count = count;
1244 INT rc;
1246 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1247 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1248 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1249 if (rc > GSUB_E_NOGLYPH)
1250 rc = count - glyph_count;
1251 else
1252 rc = 0;
1254 HeapFree(GetProcessHeap(),0,glyphs);
1255 return rc;
1258 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1260 int offset;
1261 WORD class = 0;
1262 const GDEF_ClassDefFormat1 *cf1;
1264 if (!header)
1265 return 0;
1267 offset = GET_BE_WORD(header->GlyphClassDef);
1268 if (!offset)
1269 return 0;
1271 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1272 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1274 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1276 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1277 if (index < GET_BE_WORD(cf1->GlyphCount))
1278 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1281 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1283 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1284 int i, top;
1285 top = GET_BE_WORD(cf2->ClassRangeCount);
1286 for (i = 0; i < top; i++)
1288 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1289 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1291 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1292 break;
1296 else
1297 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1299 return class;
1302 static VOID *load_gdef_table(HDC hdc)
1304 VOID* GDEF_Table = NULL;
1305 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1306 if (length != GDI_ERROR)
1308 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1309 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1310 TRACE("Loaded GDEF table of %i bytes\n",length);
1312 return GDEF_Table;
1315 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
1317 int i;
1319 if (!psc->GDEF_Table)
1320 psc->GDEF_Table = load_gdef_table(hdc);
1322 for (i = 0; i < cGlyphs; i++)
1324 WORD class;
1325 int char_count = 0;
1326 int k;
1328 for (k = 0; k < cChars; k++)
1329 if (pwLogClust[k] == i)
1330 char_count++;
1332 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1334 switch (class)
1336 case 0:
1337 case BaseGlyph:
1338 pGlyphProp[i].sva.fClusterStart = 1;
1339 pGlyphProp[i].sva.fDiacritic = 0;
1340 pGlyphProp[i].sva.fZeroWidth = 0;
1341 break;
1342 case LigatureGlyph:
1343 pGlyphProp[i].sva.fClusterStart = 1;
1344 pGlyphProp[i].sva.fDiacritic = 0;
1345 pGlyphProp[i].sva.fZeroWidth = 0;
1346 break;
1347 case MarkGlyph:
1348 pGlyphProp[i].sva.fClusterStart = 0;
1349 pGlyphProp[i].sva.fDiacritic = 1;
1350 pGlyphProp[i].sva.fZeroWidth = 1;
1351 break;
1352 case ComponentGlyph:
1353 pGlyphProp[i].sva.fClusterStart = 0;
1354 pGlyphProp[i].sva.fDiacritic = 0;
1355 pGlyphProp[i].sva.fZeroWidth = 0;
1356 break;
1357 default:
1358 ERR("Unknown glyph class %i\n",class);
1359 pGlyphProp[i].sva.fClusterStart = 1;
1360 pGlyphProp[i].sva.fDiacritic = 0;
1361 pGlyphProp[i].sva.fZeroWidth = 0;
1364 if (char_count == 0)
1365 pGlyphProp[i].sva.fClusterStart = 0;
1369 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1371 int i;
1373 for (i = 0; i < cGlyphs; i++)
1375 if (!pGlyphProp[i].sva.fClusterStart)
1377 int j;
1378 for (j = 0; j < cChars; j++)
1380 if (pwLogClust[j] == i)
1382 int k = j;
1383 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1384 k-=1;
1385 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1386 pwLogClust[j] = pwLogClust[k];
1393 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1395 if (changeCount == 0)
1396 return;
1397 else
1399 int i;
1400 int target_glyph = nextIndex - write_dir;
1401 int seeking_glyph;
1402 int target_index = -1;
1403 int replacing_glyph = -1;
1404 int changed = 0;
1405 int top_logclust = 0;
1407 if (changeCount > 0)
1409 if (write_dir > 0)
1410 target_glyph = nextIndex - changeCount;
1411 else
1412 target_glyph = nextIndex + (changeCount + 1);
1415 seeking_glyph = target_glyph;
1416 for (i = 0; i < chars; i++)
1417 if (pwLogClust[i] > top_logclust)
1418 top_logclust = pwLogClust[i];
1420 do {
1421 if (write_dir > 0)
1422 for (i = 0; i < chars; i++)
1424 if (pwLogClust[i] == seeking_glyph)
1426 target_index = i;
1427 break;
1430 else
1431 for (i = chars - 1; i >= 0; i--)
1433 if (pwLogClust[i] == seeking_glyph)
1435 target_index = i;
1436 break;
1439 if (target_index == -1)
1440 seeking_glyph ++;
1442 while (target_index == -1 && seeking_glyph <= top_logclust);
1444 if (target_index == -1)
1446 ERR("Unable to find target glyph\n");
1447 return;
1450 if (changeCount < 0)
1452 /* merge glyphs */
1453 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1455 if (pwLogClust[i] == target_glyph)
1456 continue;
1457 if(pwLogClust[i] == replacing_glyph)
1458 pwLogClust[i] = target_glyph;
1459 else
1461 changed--;
1462 if (changed >= changeCount)
1464 replacing_glyph = pwLogClust[i];
1465 pwLogClust[i] = target_glyph;
1467 else
1468 break;
1472 /* renumber trailing indexes*/
1473 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1475 if (pwLogClust[i] != target_glyph)
1476 pwLogClust[i] += changeCount;
1479 else
1481 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1482 pwLogClust[i] += changeCount;
1487 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 )
1489 if (psc->GSUB_Table)
1491 const GSUB_Feature *feature;
1492 const GSUB_LookupList *lookup;
1493 const GSUB_Header *header = psc->GSUB_Table;
1494 int lookup_index, lookup_count;
1496 feature = load_GSUB_feature(hdc, psa, psc, feat);
1497 if (!feature)
1498 return GSUB_E_NOFEATURE;
1500 TRACE("applying feature %s\n",debugstr_an(feat,4));
1501 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1502 lookup_count = GET_BE_WORD(feature->LookupCount);
1503 TRACE("%i lookups\n", lookup_count);
1504 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1506 int i;
1508 if (write_dir > 0)
1509 i = 0;
1510 else
1511 i = *pcGlyphs-1;
1512 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1513 while(i < *pcGlyphs && i >= 0)
1515 INT nextIndex;
1516 INT prevCount = *pcGlyphs;
1518 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1519 if (*pcGlyphs != prevCount)
1521 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1522 i = nextIndex;
1524 else
1525 i+=write_dir;
1528 return *pcGlyphs;
1530 return GSUB_E_NOFEATURE;
1533 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1535 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1538 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1540 if (i + delta < 0)
1541 return 0;
1542 if ( i+ delta >= cchLen)
1543 return 0;
1545 i += delta;
1547 return chars[i];
1550 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1552 if (i + delta < 0)
1554 if (psa->fLinkBefore)
1555 return jtR;
1556 else
1557 return jtU;
1559 if ( i+ delta >= cchLen)
1561 if (psa->fLinkAfter)
1562 return jtL;
1563 else
1564 return jtU;
1567 i += delta;
1569 if (context_type[i] == jtT)
1570 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1571 else
1572 return context_type[i];
1575 static inline BOOL right_join_causing(CHAR joining_type)
1577 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1580 static inline BOOL left_join_causing(CHAR joining_type)
1582 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1585 static inline BOOL word_break_causing(WCHAR chr)
1587 /* we are working within a string of characters already guareented to
1588 be within one script, Syriac, so we do not worry about any character
1589 other than the space character outside of that range */
1590 return (chr == 0 || chr == 0x20 );
1594 * ContextualShape_Arabic
1596 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1598 CHAR *context_type;
1599 INT *context_shape;
1600 INT dirR, dirL;
1601 int i;
1603 if (*pcGlyphs != cChars)
1605 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1606 return;
1609 if (!psa->fLogicalOrder && psa->fRTL)
1611 dirR = 1;
1612 dirL = -1;
1614 else
1616 dirR = -1;
1617 dirL = 1;
1620 if (!psc->GSUB_Table)
1621 psc->GSUB_Table = load_gsub_table(hdc);
1623 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1624 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1626 for (i = 0; i < cChars; i++)
1627 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1629 for (i = 0; i < cChars; i++)
1631 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1632 context_shape[i] = Xr;
1633 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1634 context_shape[i] = Xl;
1635 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)))
1636 context_shape[i] = Xm;
1637 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1638 context_shape[i] = Xr;
1639 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1640 context_shape[i] = Xl;
1641 else
1642 context_shape[i] = Xn;
1645 /* Contextual Shaping */
1646 i = 0;
1647 while(i < *pcGlyphs)
1649 BOOL shaped = FALSE;
1651 if (psc->GSUB_Table)
1653 INT nextIndex;
1654 INT prevCount = *pcGlyphs;
1655 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1656 if (nextIndex > GSUB_E_NOGLYPH)
1658 i = nextIndex;
1659 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1661 shaped = (nextIndex > GSUB_E_NOGLYPH);
1664 if (!shaped)
1666 if (context_shape[i] == Xn)
1668 WORD newGlyph = pwOutGlyphs[i];
1669 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1671 /* fall back to presentation form B */
1672 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1673 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1674 pwOutGlyphs[i] = newGlyph;
1677 i++;
1681 HeapFree(GetProcessHeap(),0,context_shape);
1682 HeapFree(GetProcessHeap(),0,context_type);
1686 * ContextualShape_Syriac
1689 #define ALAPH 0x710
1690 #define DALATH 0x715
1691 #define RISH 0x72A
1693 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1695 CHAR *context_type;
1696 INT *context_shape;
1697 INT dirR, dirL;
1698 int i;
1700 if (*pcGlyphs != cChars)
1702 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1703 return;
1706 if (!psa->fLogicalOrder && psa->fRTL)
1708 dirR = 1;
1709 dirL = -1;
1711 else
1713 dirR = -1;
1714 dirL = 1;
1717 if (!psc->GSUB_Table)
1718 psc->GSUB_Table = load_gsub_table(hdc);
1720 if (!psc->GSUB_Table)
1721 return;
1723 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1724 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1726 for (i = 0; i < cChars; i++)
1727 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1729 for (i = 0; i < cChars; i++)
1731 if (pwcChars[i] == ALAPH)
1733 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1735 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1736 context_shape[i] = Afj;
1737 else if ( rchar != DALATH && rchar != RISH &&
1738 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1739 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1740 context_shape[i] = Afn;
1741 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1742 context_shape[i] = Afx;
1743 else
1744 context_shape[i] = Xn;
1746 else if (context_type[i] == jtR &&
1747 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1748 context_shape[i] = Xr;
1749 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1750 context_shape[i] = Xl;
1751 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)))
1752 context_shape[i] = Xm;
1753 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1754 context_shape[i] = Xr;
1755 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1756 context_shape[i] = Xl;
1757 else
1758 context_shape[i] = Xn;
1761 /* Contextual Shaping */
1762 i = 0;
1763 while(i < *pcGlyphs)
1765 INT nextIndex;
1766 INT prevCount = *pcGlyphs;
1767 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1768 if (nextIndex > GSUB_E_NOGLYPH)
1770 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1771 i = nextIndex;
1773 else
1774 i++;
1777 HeapFree(GetProcessHeap(),0,context_shape);
1778 HeapFree(GetProcessHeap(),0,context_type);
1782 * ContextualShape_Phags_pa
1785 #define phags_pa_CANDRABINDU 0xA873
1786 #define phags_pa_START 0xA840
1787 #define phags_pa_END 0xA87F
1789 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1791 INT *context_shape;
1792 INT dirR, dirL;
1793 int i;
1795 if (*pcGlyphs != cChars)
1797 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1798 return;
1801 if (!psa->fLogicalOrder && psa->fRTL)
1803 dirR = 1;
1804 dirL = -1;
1806 else
1808 dirR = -1;
1809 dirL = 1;
1812 if (!psc->GSUB_Table)
1813 psc->GSUB_Table = load_gsub_table(hdc);
1815 if (!psc->GSUB_Table)
1816 return;
1818 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1820 for (i = 0; i < cChars; i++)
1822 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1824 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1825 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1826 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1827 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1829 if (jrchar && jlchar)
1830 context_shape[i] = Xm;
1831 else if (jrchar)
1832 context_shape[i] = Xr;
1833 else if (jlchar)
1834 context_shape[i] = Xl;
1835 else
1836 context_shape[i] = Xn;
1838 else
1839 context_shape[i] = -1;
1842 /* Contextual Shaping */
1843 i = 0;
1844 while(i < *pcGlyphs)
1846 if (context_shape[i] >= 0)
1848 INT nextIndex;
1849 INT prevCount = *pcGlyphs;
1850 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1851 if (nextIndex > GSUB_E_NOGLYPH)
1853 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1854 i = nextIndex;
1856 else
1857 i++;
1859 else
1860 i++;
1863 HeapFree(GetProcessHeap(),0,context_shape);
1866 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1868 int i;
1870 /* Replace */
1871 pwOutChars[cWalk] = replacements[0];
1872 cWalk=cWalk+1;
1874 /* Insert */
1875 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1877 int j;
1878 for (j = *pcChars; j > cWalk; j--)
1879 pwOutChars[j] = pwOutChars[j-1];
1880 *pcChars= *pcChars+1;
1881 pwOutChars[cWalk] = replacements[i];
1882 cWalk = cWalk+1;
1886 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1888 int i;
1889 int cWalk;
1891 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1893 for (i = 0; vowels[i].base != 0x0; i++)
1895 if (pwOutChars[cWalk] == vowels[i].base)
1897 int o = 0;
1898 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1899 if (vowels[i].parts[1]) { cWalk++; o++; }
1900 if (vowels[i].parts[2]) { cWalk++; o++; }
1901 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1902 break;
1908 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1910 int i;
1911 int offset = 0;
1912 int cWalk;
1914 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1916 for (i = 0; consonants[i].output!= 0x0; i++)
1918 int j;
1919 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1920 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1921 break;
1923 if (consonants[i].parts[j]==0x0) /* matched all */
1925 int k;
1926 j--;
1927 pwOutChars[cWalk] = consonants[i].output;
1928 for(k = cWalk+1; k < *pcChars - j; k++)
1929 pwOutChars[k] = pwOutChars[k+j];
1930 *pcChars = *pcChars - j;
1931 for (k = j ; k > 0; k--)
1932 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1933 offset += j;
1934 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1935 pwLogClust[k]--;
1936 break;
1939 cWalk++;
1943 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1945 if (s->ralf >= 0)
1947 int j;
1948 WORD Ra = pwChar[s->start];
1949 WORD H = pwChar[s->start+1];
1951 TRACE("Doing reorder of Ra to %i\n",s->base);
1952 for (j = s->start; j < s->base-1; j++)
1953 pwChar[j] = pwChar[j+2];
1954 pwChar[s->base-1] = Ra;
1955 pwChar[s->base] = H;
1957 s->ralf = s->base-1;
1958 s->base -= 2;
1962 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1964 if (s->ralf >= 0)
1966 int j,loc;
1967 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1968 WORD Ra = pwChar[s->start];
1969 WORD H = pwChar[s->start+1];
1970 for (loc = s->end; loc > stop; loc--)
1971 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1972 break;
1974 TRACE("Doing reorder of Ra to %i\n",loc);
1975 for (j = s->start; j < loc-1; j++)
1976 pwChar[j] = pwChar[j+2];
1977 pwChar[loc-1] = Ra;
1978 pwChar[loc] = H;
1980 s->ralf = loc-1;
1981 s->base -= 2;
1982 if (s->blwf >= 0) s->blwf -= 2;
1983 if (s->pref >= 0) s->pref -= 2;
1987 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1989 if (s->ralf >= 0)
1991 int j;
1992 WORD Ra = pwChar[s->start];
1993 WORD H = pwChar[s->start+1];
1995 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1996 for (j = s->start; j < s->end-1; j++)
1997 pwChar[j] = pwChar[j+2];
1998 pwChar[s->end-1] = Ra;
1999 pwChar[s->end] = H;
2001 s->ralf = s->end-1;
2002 s->base -= 2;
2003 if (s->blwf >= 0) s->blwf -= 2;
2004 if (s->pref >= 0) s->pref -= 2;
2008 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2010 int i;
2012 /* reorder Matras */
2013 if (s->end > s->base)
2015 for (i = 1; i <= s->end-s->base; i++)
2017 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2019 int j;
2020 WCHAR c = pwChar[s->base+i];
2021 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
2022 for (j = s->base+i; j > s->base; j--)
2023 pwChar[j] = pwChar[j-1];
2024 pwChar[s->base] = c;
2026 if (s->ralf >= s->base) s->ralf++;
2027 if (s->blwf >= s->base) s->blwf++;
2028 if (s->pref >= s->base) s->pref++;
2029 s->base ++;
2035 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2037 int i;
2039 /* reorder Matras */
2040 if (s->end > s->base)
2042 for (i = 1; i <= s->end-s->base; i++)
2044 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2046 int j;
2047 WCHAR c = pwChar[s->base+i];
2048 TRACE("Doing reorder of %x to %i\n",c,s->start);
2049 for (j = s->base+i; j > s->start; j--)
2050 pwChar[j] = pwChar[j-1];
2051 pwChar[s->start] = c;
2053 if (s->ralf >= 0) s->ralf++;
2054 if (s->blwf >= 0) s->blwf++;
2055 if (s->pref >= 0) s->pref++;
2056 s->base ++;
2062 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2064 if (s->blwf >= 0 && g->blwf > g->base)
2066 int j,loc;
2067 int g_offset;
2068 for (loc = s->end; loc > s->blwf; loc--)
2069 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2070 break;
2072 g_offset = (loc - s->blwf) - 1;
2074 if (loc != s->blwf)
2076 WORD blwf = glyphs[g->blwf];
2077 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2078 /* do not care about the pwChar array anymore, just the glyphs */
2079 for (j = 0; j < g_offset; j++)
2080 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2081 glyphs[g->blwf + g_offset] = blwf;
2086 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2088 int i;
2090 /* reorder previously moved Matras to correct position*/
2091 for (i = s->start; i < s->base; i++)
2093 if (lexical(pwChar[i]) == lex_Matra_pre)
2095 int j;
2096 int g_start = g->start + i - s->start;
2097 if (g_start < g->base -1 )
2099 WCHAR og = glyphs[g_start];
2100 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2101 for (j = g_start; j < g->base-1; j++)
2102 glyphs[j] = glyphs[j+1];
2103 glyphs[g->base-1] = og;
2109 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2111 if (s->pref >= 0 && g->pref > g->base)
2113 int j;
2114 WCHAR og = glyphs[g->pref];
2115 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2116 for (j = g->pref; j > g->base; j--)
2117 glyphs[j] = glyphs[j-1];
2118 glyphs[g->base] = og;
2122 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2124 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2125 if (s->start == s->base && s->base == s->end) return;
2126 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2128 Reorder_Ra_follows_base(pwChar, s, lexical);
2129 Reorder_Matra_precede_base(pwChar, s, lexical);
2132 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2134 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2135 if (s->start == s->base && s->base == s->end) return;
2136 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2138 Reorder_Ra_follows_matra(pwChar, s, lexical);
2139 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2142 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2144 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2145 if (s->start == s->base && s->base == s->end) return;
2146 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2148 Reorder_Ra_follows_base(pwChar, s, lexical);
2149 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2152 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2154 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2155 if (s->start == s->base && s->base == s->end) return;
2156 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2158 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2159 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2162 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2164 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2165 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2166 if (s->start == s->base && s->base == s->end) return;
2167 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2169 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2172 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2174 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2175 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2176 if (s->start == s->base && s->base == s->end) return;
2177 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2179 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2180 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2184 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2186 if (shift == 0)
2187 return;
2189 if (glyph_index->start > index)
2190 glyph_index->start += shift;
2191 if (glyph_index->base > index)
2192 glyph_index->base+= shift;
2193 if (glyph_index->end > index)
2194 glyph_index->end+= shift;
2195 if (glyph_index->ralf > index)
2196 glyph_index->ralf+= shift;
2197 if (glyph_index->blwf > index)
2198 glyph_index->blwf+= shift;
2199 if (glyph_index->pref > index)
2200 glyph_index->pref+= shift;
2203 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 )
2205 int index = glyph_index->start;
2207 if (!feature)
2208 return;
2210 while(index <= glyph_index->end)
2212 INT nextIndex;
2213 INT prevCount = *pcGlyphs;
2214 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2215 if (nextIndex > GSUB_E_NOGLYPH)
2217 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2218 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2219 index = nextIndex;
2221 else
2222 index++;
2226 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2228 int i = 0;
2229 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)))))
2230 i++;
2231 if (index + i <= end-1)
2232 return index + i;
2233 else
2234 return -1;
2237 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)
2239 INT index, nextIndex;
2240 INT count,g_offset;
2242 count = syllable->base - syllable->start;
2244 g_offset = 0;
2245 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2246 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2248 INT prevCount = *pcGlyphs;
2249 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2250 if (nextIndex > GSUB_E_NOGLYPH)
2252 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2253 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2254 g_offset += (*pcGlyphs - prevCount);
2257 index+=2;
2258 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2262 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)
2264 INT nextIndex;
2265 INT prevCount = *pcGlyphs;
2267 if (syllable->ralf >= 0)
2269 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2270 if (nextIndex > GSUB_E_NOGLYPH)
2272 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2273 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2278 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2280 int i = 0;
2281 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2282 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2283 is_consonant(lexical(pwChars[index+i+1])))))
2284 i++;
2285 if (index + i <= end-1)
2286 return index+i;
2287 else
2288 return -1;
2291 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)
2293 INT index, nextIndex;
2294 INT count, g_offset=0;
2295 INT ralf = syllable->ralf;
2297 count = syllable->end - syllable->base;
2299 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2301 while (index >= 0)
2303 INT prevCount = *pcGlyphs;
2304 if (ralf >=0 && ralf < index)
2306 g_offset--;
2307 ralf = -1;
2310 if (!modern)
2312 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2313 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2314 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2317 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2318 if (nextIndex > GSUB_E_NOGLYPH)
2320 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2321 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2322 g_offset += (*pcGlyphs - prevCount);
2324 else if (!modern)
2326 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2327 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2328 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2331 index+=2;
2332 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2336 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)
2338 int c;
2339 int overall_shift = 0;
2340 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2341 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2342 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2343 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2344 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2345 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2346 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2347 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2348 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2349 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2350 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2351 IndicSyllable glyph_indexs;
2353 for (c = 0; c < syllable_count; c++)
2355 int old_end;
2356 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2357 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2358 old_end = glyph_indexs.end;
2360 if (locl)
2362 TRACE("applying feature locl\n");
2363 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2365 if (nukt)
2367 TRACE("applying feature nukt\n");
2368 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2370 if (akhn)
2372 TRACE("applying feature akhn\n");
2373 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2376 if (rphf)
2377 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2378 if (rkrf)
2380 TRACE("applying feature rkrf\n");
2381 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2383 if (pref)
2384 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2385 if (blwf)
2387 if (!modern)
2388 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2390 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2393 if (half)
2394 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2395 if (pstf)
2397 TRACE("applying feature pstf\n");
2398 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2400 if (vatu)
2402 TRACE("applying feature vatu\n");
2403 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2405 if (cjct)
2407 TRACE("applying feature cjct\n");
2408 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2411 if (second_reorder)
2412 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2414 overall_shift += glyph_indexs.end - old_end;
2418 static inline int unicode_lex(WCHAR c)
2420 int type;
2422 if (!c) return lex_Generic;
2423 if (c == 0x200D) return lex_ZWJ;
2424 if (c == 0x200C) return lex_ZWNJ;
2425 if (c == 0x00A0) return lex_NBSP;
2427 type = get_table_entry( indic_syllabic_table, c );
2429 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2431 switch( type )
2433 case 0x0d07: /* Unknown */
2434 case 0x0e07: /* Unknwon */
2435 default: return lex_Generic;
2436 case 0x0001:
2437 case 0x0002:
2438 case 0x0011:
2439 case 0x0012:
2440 case 0x0013:
2441 case 0x0014: return lex_Modifier;
2442 case 0x0003:
2443 case 0x0009:
2444 case 0x000a:
2445 case 0x000b:
2446 case 0x000d:
2447 case 0x000e:
2448 case 0x000f:
2449 case 0x0010: return lex_Consonant;
2450 case 0x0004: return lex_Nukta;
2451 case 0x0005: return lex_Halant;
2452 case 0x0006:
2453 case 0x0008: return lex_Vowel;
2454 case 0x0007:
2455 case 0x0107: return lex_Matra_post;
2456 case 0x0207:
2457 case 0x0307: return lex_Matra_pre;
2458 case 0x0807:
2459 case 0x0907:
2460 case 0x0a07:
2461 case 0x0b07:
2462 case 0x0c07:
2463 case 0x0407: return lex_Composed_Vowel;
2464 case 0x0507: return lex_Matra_above;
2465 case 0x0607: return lex_Matra_below;
2466 case 0x000c: return lex_Ra;
2470 static int sinhala_lex(WCHAR c)
2472 switch (c)
2474 case 0x0DDA:
2475 case 0x0DDD:
2476 case 0x0DDC:
2477 case 0x0DDE: return lex_Matra_post;
2478 default:
2479 return unicode_lex(c);
2483 static const VowelComponents Sinhala_vowels[] = {
2484 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2485 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2486 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2487 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2488 {0x0000, {0x0000,0x0000,0x0}}};
2490 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2492 int cCount = cChars;
2493 int i;
2494 WCHAR *input;
2495 IndicSyllable *syllables = NULL;
2496 int syllable_count = 0;
2498 if (*pcGlyphs != cChars)
2500 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2501 return;
2504 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2506 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2508 /* Step 1: Decompose multi part vowels */
2509 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2511 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2513 /* Step 2: Reorder within Syllables */
2514 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2515 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2517 /* Step 3: Strip dangling joiners */
2518 for (i = 0; i < cCount; i++)
2520 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2521 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2522 input[i] = 0x0020;
2525 /* Step 4: Base Form application to syllables */
2526 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2527 *pcGlyphs = cCount;
2528 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2530 HeapFree(GetProcessHeap(),0,input);
2531 HeapFree(GetProcessHeap(),0,syllables);
2534 static int devanagari_lex(WCHAR c)
2536 switch (c)
2538 case 0x0930: return lex_Ra;
2539 default:
2540 return unicode_lex(c);
2544 static const ConsonantComponents Devanagari_consonants[] ={
2545 {{0x0928, 0x093C, 0x00000}, 0x0929},
2546 {{0x0930, 0x093C, 0x00000}, 0x0931},
2547 {{0x0933, 0x093C, 0x00000}, 0x0934},
2548 {{0x0915, 0x093C, 0x00000}, 0x0958},
2549 {{0x0916, 0x093C, 0x00000}, 0x0959},
2550 {{0x0917, 0x093C, 0x00000}, 0x095A},
2551 {{0x091C, 0x093C, 0x00000}, 0x095B},
2552 {{0x0921, 0x093C, 0x00000}, 0x095C},
2553 {{0x0922, 0x093C, 0x00000}, 0x095D},
2554 {{0x092B, 0x093C, 0x00000}, 0x095E},
2555 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2557 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2559 int cCount = cChars;
2560 WCHAR *input;
2561 IndicSyllable *syllables = NULL;
2562 int syllable_count = 0;
2563 BOOL modern = get_GSUB_Indic2(psa, psc);
2565 if (*pcGlyphs != cChars)
2567 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2568 return;
2571 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2572 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2574 /* Step 1: Compose Consonant and Nukta */
2575 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2576 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2578 /* Step 2: Reorder within Syllables */
2579 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2580 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2581 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2582 *pcGlyphs = cCount;
2584 /* Step 3: Base Form application to syllables */
2585 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2587 HeapFree(GetProcessHeap(),0,input);
2588 HeapFree(GetProcessHeap(),0,syllables);
2591 static int bengali_lex(WCHAR c)
2593 switch (c)
2595 case 0x09B0: return lex_Ra;
2596 default:
2597 return unicode_lex(c);
2601 static const VowelComponents Bengali_vowels[] = {
2602 {0x09CB, {0x09C7,0x09BE,0x0000}},
2603 {0x09CC, {0x09C7,0x09D7,0x0000}},
2604 {0x0000, {0x0000,0x0000,0x0000}}};
2606 static const ConsonantComponents Bengali_consonants[] = {
2607 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2608 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2609 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2610 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2611 {{0x0000,0x0000,0x0000}, 0x0000}};
2613 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2615 int cCount = cChars;
2616 WCHAR *input;
2617 IndicSyllable *syllables = NULL;
2618 int syllable_count = 0;
2619 BOOL modern = get_GSUB_Indic2(psa, psc);
2621 if (*pcGlyphs != cChars)
2623 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2624 return;
2627 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2628 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2630 /* Step 1: Decompose Vowels and Compose Consonents */
2631 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2632 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2633 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2635 /* Step 2: Reorder within Syllables */
2636 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2637 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2638 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2639 *pcGlyphs = cCount;
2641 /* Step 3: Initial form is only applied to the beginning of words */
2642 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2644 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2646 int index = cCount;
2647 int gCount = 1;
2648 if (index > 0) index++;
2650 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2654 /* Step 4: Base Form application to syllables */
2655 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2657 HeapFree(GetProcessHeap(),0,input);
2658 HeapFree(GetProcessHeap(),0,syllables);
2661 static int gurmukhi_lex(WCHAR c)
2663 if (c == 0x0A71)
2664 return lex_Modifier;
2665 else
2666 return unicode_lex(c);
2669 static const ConsonantComponents Gurmukhi_consonants[] = {
2670 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2671 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2672 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2673 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2674 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2675 {{0x0000,0x0000,0x0000}, 0x0000}};
2677 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2679 int cCount = cChars;
2680 WCHAR *input;
2681 IndicSyllable *syllables = NULL;
2682 int syllable_count = 0;
2683 BOOL modern = get_GSUB_Indic2(psa, psc);
2685 if (*pcGlyphs != cChars)
2687 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2688 return;
2691 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2692 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2694 /* Step 1: Compose Consonents */
2695 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2696 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2698 /* Step 2: Reorder within Syllables */
2699 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2700 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2701 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2702 *pcGlyphs = cCount;
2704 /* Step 3: Base Form application to syllables */
2705 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2707 HeapFree(GetProcessHeap(),0,input);
2708 HeapFree(GetProcessHeap(),0,syllables);
2711 static int gujarati_lex(WCHAR c)
2713 switch (c)
2715 case 0x0AB0: return lex_Ra;
2716 default:
2717 return unicode_lex(c);
2721 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2723 int cCount = cChars;
2724 WCHAR *input;
2725 IndicSyllable *syllables = NULL;
2726 int syllable_count = 0;
2727 BOOL modern = get_GSUB_Indic2(psa, psc);
2729 if (*pcGlyphs != cChars)
2731 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2732 return;
2735 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2736 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2738 /* Step 1: Reorder within Syllables */
2739 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2740 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2741 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2742 *pcGlyphs = cCount;
2744 /* Step 2: Base Form application to syllables */
2745 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2747 HeapFree(GetProcessHeap(),0,input);
2748 HeapFree(GetProcessHeap(),0,syllables);
2751 static int oriya_lex(WCHAR c)
2753 switch (c)
2755 case 0x0B30: return lex_Ra;
2756 default:
2757 return unicode_lex(c);
2761 static const VowelComponents Oriya_vowels[] = {
2762 {0x0B48, {0x0B47,0x0B56,0x0000}},
2763 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2764 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2765 {0x0000, {0x0000,0x0000,0x0000}}};
2767 static const ConsonantComponents Oriya_consonants[] = {
2768 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2769 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2770 {{0x0000,0x0000,0x0000}, 0x0000}};
2772 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2774 int cCount = cChars;
2775 WCHAR *input;
2776 IndicSyllable *syllables = NULL;
2777 int syllable_count = 0;
2778 BOOL modern = get_GSUB_Indic2(psa, psc);
2780 if (*pcGlyphs != cChars)
2782 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2783 return;
2786 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2787 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2789 /* Step 1: Decompose Vowels and Compose Consonents */
2790 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2791 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2792 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2794 /* Step 2: Reorder within Syllables */
2795 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2796 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2797 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2798 *pcGlyphs = cCount;
2800 /* Step 3: Base Form application to syllables */
2801 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2803 HeapFree(GetProcessHeap(),0,input);
2804 HeapFree(GetProcessHeap(),0,syllables);
2807 static int tamil_lex(WCHAR c)
2809 return unicode_lex(c);
2812 static const VowelComponents Tamil_vowels[] = {
2813 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2814 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2815 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2816 {0x0000, {0x0000,0x0000,0x0000}}};
2818 static const ConsonantComponents Tamil_consonants[] = {
2819 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2820 {{0x0000,0x0000,0x0000}, 0x0000}};
2822 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2824 int cCount = cChars;
2825 WCHAR *input;
2826 IndicSyllable *syllables = NULL;
2827 int syllable_count = 0;
2828 BOOL modern = get_GSUB_Indic2(psa, psc);
2830 if (*pcGlyphs != cChars)
2832 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2833 return;
2836 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2837 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2839 /* Step 1: Decompose Vowels and Compose Consonents */
2840 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2841 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2842 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2844 /* Step 2: Reorder within Syllables */
2845 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2846 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2847 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2848 *pcGlyphs = cCount;
2850 /* Step 3: Base Form application to syllables */
2851 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2853 HeapFree(GetProcessHeap(),0,input);
2854 HeapFree(GetProcessHeap(),0,syllables);
2857 static int telugu_lex(WCHAR c)
2859 switch (c)
2861 case 0x0C43:
2862 case 0x0C44: return lex_Modifier;
2863 default:
2864 return unicode_lex(c);
2868 static const VowelComponents Telugu_vowels[] = {
2869 {0x0C48, {0x0C46,0x0C56,0x0000}},
2870 {0x0000, {0x0000,0x0000,0x0000}}};
2872 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2874 int cCount = cChars;
2875 WCHAR *input;
2876 IndicSyllable *syllables = NULL;
2877 int syllable_count = 0;
2878 BOOL modern = get_GSUB_Indic2(psa, psc);
2880 if (*pcGlyphs != cChars)
2882 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2883 return;
2886 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2887 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2889 /* Step 1: Decompose Vowels */
2890 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2891 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2893 /* Step 2: Reorder within Syllables */
2894 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2895 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2896 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2897 *pcGlyphs = cCount;
2899 /* Step 3: Base Form application to syllables */
2900 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2902 HeapFree(GetProcessHeap(),0,input);
2903 HeapFree(GetProcessHeap(),0,syllables);
2906 static int kannada_lex(WCHAR c)
2908 switch (c)
2910 case 0x0CB0: return lex_Ra;
2911 default:
2912 return unicode_lex(c);
2916 static const VowelComponents Kannada_vowels[] = {
2917 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2918 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2919 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2920 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2921 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2922 {0x0000, {0x0000,0x0000,0x0000}}};
2924 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2926 int cCount = cChars;
2927 WCHAR *input;
2928 IndicSyllable *syllables = NULL;
2929 int syllable_count = 0;
2930 BOOL modern = get_GSUB_Indic2(psa, psc);
2932 if (*pcGlyphs != cChars)
2934 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2935 return;
2938 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2939 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2941 /* Step 1: Decompose Vowels */
2942 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2943 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2945 /* Step 2: Reorder within Syllables */
2946 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2947 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2948 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2949 *pcGlyphs = cCount;
2951 /* Step 3: Base Form application to syllables */
2952 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2954 HeapFree(GetProcessHeap(),0,input);
2955 HeapFree(GetProcessHeap(),0,syllables);
2958 static int malayalam_lex(WCHAR c)
2960 return unicode_lex(c);
2963 static const VowelComponents Malayalam_vowels[] = {
2964 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2965 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2966 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2967 {0x0000, {0x0000,0x0000,0x0000}}};
2969 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2971 int cCount = cChars;
2972 WCHAR *input;
2973 IndicSyllable *syllables = NULL;
2974 int syllable_count = 0;
2975 BOOL modern = get_GSUB_Indic2(psa, psc);
2977 if (*pcGlyphs != cChars)
2979 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2980 return;
2983 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2984 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2986 /* Step 1: Decompose Vowels */
2987 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2988 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2990 /* Step 2: Reorder within Syllables */
2991 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2992 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2993 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2994 *pcGlyphs = cCount;
2996 /* Step 3: Base Form application to syllables */
2997 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2999 HeapFree(GetProcessHeap(),0,input);
3000 HeapFree(GetProcessHeap(),0,syllables);
3003 static int khmer_lex(WCHAR c)
3005 return unicode_lex(c);
3008 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3010 int cCount = cChars;
3011 WCHAR *input;
3012 IndicSyllable *syllables = NULL;
3013 int syllable_count = 0;
3015 if (*pcGlyphs != cChars)
3017 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3018 return;
3021 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
3022 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3024 /* Step 1: Reorder within Syllables */
3025 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
3026 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3027 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3028 *pcGlyphs = cCount;
3030 /* Step 2: Base Form application to syllables */
3031 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
3033 HeapFree(GetProcessHeap(),0,input);
3034 HeapFree(GetProcessHeap(),0,syllables);
3037 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)
3039 int i,k;
3041 for (i = 0; i < cGlyphs; i++)
3043 int char_index[20];
3044 int char_count = 0;
3046 for (k = 0; k < cChars; k++)
3048 if (pwLogClust[k] == i)
3050 char_index[char_count] = k;
3051 char_count++;
3055 if (char_count == 0)
3056 continue;
3058 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3060 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3061 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3063 else
3064 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3067 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3068 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3071 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 )
3073 int i,k;
3074 int initGlyph, finaGlyph;
3075 INT dirR, dirL;
3076 BYTE *spaces;
3078 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3079 memset(spaces,0,cGlyphs);
3081 if (!psa->fLogicalOrder && psa->fRTL)
3083 initGlyph = cGlyphs-1;
3084 finaGlyph = 0;
3085 dirR = 1;
3086 dirL = -1;
3088 else
3090 initGlyph = 0;
3091 finaGlyph = cGlyphs-1;
3092 dirR = -1;
3093 dirL = 1;
3096 for (i = 0; i < cGlyphs; i++)
3098 for (k = 0; k < cChars; k++)
3099 if (pwLogClust[k] == i)
3101 if (pwcChars[k] == 0x0020)
3102 spaces[i] = 1;
3106 for (i = 0; i < cGlyphs; i++)
3108 int char_index[20];
3109 int char_count = 0;
3110 BOOL isInit, isFinal;
3112 for (k = 0; k < cChars; k++)
3114 if (pwLogClust[k] == i)
3116 char_index[char_count] = k;
3117 char_count++;
3121 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3122 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3124 if (char_count == 0)
3125 continue;
3127 if (char_count == 1)
3129 if (pwcChars[char_index[0]] == 0x0020) /* space */
3131 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3132 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3134 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3135 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3136 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3138 if (!isInit && !isFinal)
3139 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3140 else if (isInit)
3141 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3142 else
3143 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3145 else if (!isInit)
3147 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3148 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3149 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3150 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3151 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3152 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3153 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3154 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3155 else
3156 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3158 else if (!isInit && !isFinal)
3159 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3160 else
3161 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3163 else if (char_count == 2)
3165 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3166 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3167 else if (!isInit)
3168 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3169 else
3170 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3172 else if (!isInit && !isFinal)
3173 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3174 else
3175 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3178 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3179 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3180 HeapFree(GetProcessHeap(),0,spaces);
3183 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 )
3185 int i,k;
3186 int finaGlyph;
3187 INT dirL;
3188 BYTE *spaces;
3190 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3191 memset(spaces,0,cGlyphs);
3193 if (!psa->fLogicalOrder && psa->fRTL)
3195 finaGlyph = 0;
3196 dirL = -1;
3198 else
3200 finaGlyph = cGlyphs-1;
3201 dirL = 1;
3204 for (i = 0; i < cGlyphs; i++)
3206 for (k = 0; k < cChars; k++)
3207 if (pwLogClust[k] == i)
3209 if (pwcChars[k] == 0x0020)
3210 spaces[i] = 1;
3214 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3216 for (i = 0; i < cGlyphs; i++)
3218 int char_index[20];
3219 int char_count = 0;
3221 for (k = 0; k < cChars; k++)
3223 if (pwLogClust[k] == i)
3225 char_index[char_count] = k;
3226 char_count++;
3230 if (char_count == 0)
3231 continue;
3233 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3235 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3236 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3238 else if (i == finaGlyph)
3239 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3240 else
3241 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3243 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3244 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3245 pGlyphProp[i].sva.fClusterStart = 0;
3248 HeapFree(GetProcessHeap(),0,spaces);
3249 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3251 /* Do not allow justification between marks and their base */
3252 for (i = 0; i < cGlyphs; i++)
3254 if (!pGlyphProp[i].sva.fClusterStart)
3255 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3259 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)
3261 int i,k;
3263 for (i = 0; i < cGlyphs; i++)
3265 int char_index[20];
3266 int char_count = 0;
3268 for (k = 0; k < cChars; k++)
3270 if (pwLogClust[k] == i)
3272 char_index[char_count] = k;
3273 char_count++;
3277 if (char_count == 0)
3278 continue;
3280 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3282 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3283 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3285 else
3286 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3288 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3289 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3292 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)
3294 int i,k;
3296 for (i = 0; i < cGlyphs; i++)
3298 int char_index[20];
3299 int char_count = 0;
3301 for (k = 0; k < cChars; k++)
3303 if (pwLogClust[k] == i)
3305 char_index[char_count] = k;
3306 char_count++;
3310 if (char_count == 0)
3311 continue;
3313 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3315 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3316 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3318 else
3319 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3321 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3322 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3324 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3325 for (i = 0; i < cGlyphs; i++)
3327 if (!pGlyphProp[i].sva.fClusterStart)
3329 pGlyphProp[i].sva.fDiacritic = 0;
3330 pGlyphProp[i].sva.fZeroWidth = 0;
3335 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, BOOL use_syllables, BOOL override_gsub)
3337 int i,k;
3339 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3340 for (i = 0; i < cGlyphs; i++)
3342 int char_index[20];
3343 int char_count = 0;
3345 for (k = 0; k < cChars; k++)
3347 if (pwLogClust[k] == i)
3349 char_index[char_count] = k;
3350 char_count++;
3354 if (override_gsub)
3356 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3357 pGlyphProp[i].sva.fDiacritic = FALSE;
3358 pGlyphProp[i].sva.fZeroWidth = FALSE;
3361 if (char_count == 0)
3362 continue;
3364 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3366 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3367 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3369 else
3370 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3372 pGlyphProp[i].sva.fClusterStart = 0;
3373 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3374 switch (lexical(pwcChars[char_index[k]]))
3376 case lex_Matra_pre:
3377 case lex_Matra_post:
3378 case lex_Matra_above:
3379 case lex_Matra_below:
3380 case lex_Modifier:
3381 case lex_Halant:
3382 break;
3383 case lex_ZWJ:
3384 case lex_ZWNJ:
3385 /* check for dangling joiners */
3386 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3387 pGlyphProp[i].sva.fClusterStart = 1;
3388 else
3389 k = char_count;
3390 break;
3391 default:
3392 pGlyphProp[i].sva.fClusterStart = 1;
3393 break;
3397 if (use_syllables)
3399 IndicSyllable *syllables = NULL;
3400 int syllable_count = 0;
3401 BOOL modern = get_GSUB_Indic2(psa, psc);
3403 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3405 for (i = 0; i < syllable_count; i++)
3407 int j;
3408 WORD g = pwLogClust[syllables[i].start];
3409 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3411 if (pwLogClust[j] != g)
3413 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3414 pwLogClust[j] = g;
3419 HeapFree(GetProcessHeap(), 0, syllables);
3422 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3425 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 )
3427 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3430 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 )
3432 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3435 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 )
3437 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3440 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 )
3442 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3445 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 )
3447 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3450 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 )
3452 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3455 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 )
3457 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3460 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 )
3462 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3465 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 )
3467 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3470 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 )
3472 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3475 static void ShapeCharGlyphProp_Khmer( 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 )
3477 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3480 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)
3482 if (ShapingData[psa->eScript].charGlyphPropProc)
3483 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3484 else
3485 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3488 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3490 if (!psc->GSUB_Table)
3491 psc->GSUB_Table = load_gsub_table(hdc);
3493 if (ShapingData[psa->eScript].contextProc)
3494 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3497 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)
3499 int i;
3500 INT dirL;
3502 if (!rpRangeProperties)
3503 return;
3505 if (!psc->GSUB_Table)
3506 psc->GSUB_Table = load_gsub_table(hdc);
3508 if (!psc->GSUB_Table)
3509 return;
3511 if (!psa->fLogicalOrder && psa->fRTL)
3512 dirL = -1;
3513 else
3514 dirL = 1;
3516 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3518 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3519 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3523 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3525 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3526 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3528 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3531 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3533 const GSUB_Feature *feature;
3534 int i;
3536 if (!ShapingData[psa->eScript].requiredFeatures)
3537 return S_OK;
3539 if (!psc->GSUB_Table)
3540 psc->GSUB_Table = load_gsub_table(hdc);
3542 /* we need to have at least one of the required features */
3543 i = 0;
3544 while (ShapingData[psa->eScript].requiredFeatures[i])
3546 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3547 if (feature)
3548 return S_OK;
3549 i++;
3552 return USP_E_SCRIPT_NOT_IN_FONT;