ddraw/tests: Properly release no longer used interfaces.
[wine/multimedia.git] / dlls / usp10 / shape.c
blobaacb998b1cac5f7a7a6e54df297a775ce0e02cbf
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "usp10.h"
29 #include "winternl.h"
31 #include "usp10_internal.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
37 #define FIRST_ARABIC_CHAR 0x0600
38 #define LAST_ARABIC_CHAR 0x06ff
40 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
41 WCHAR*, INT, WORD*, INT*, INT, WORD*);
43 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
59 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
60 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
61 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
62 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
63 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
64 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
65 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
66 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
67 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
68 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74 extern const unsigned short indic_syllabic_table[];
75 extern const unsigned short wine_shaping_table[];
76 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
78 enum joining_types {
79 jtU,
80 jtT,
81 jtR,
82 jtL,
83 jtD,
84 jtC
87 enum joined_forms {
88 Xn=0,
89 Xr,
90 Xl,
91 Xm,
92 /* Syriac Alaph */
93 Afj,
94 Afn,
95 Afx
98 #ifdef WORDS_BIGENDIAN
99 #define GET_BE_WORD(x) (x)
100 #else
101 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
102 #endif
104 /* These are all structures needed for the GSUB table */
105 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
106 #define GSUB_E_NOFEATURE -2
107 #define GSUB_E_NOGLYPH -1
109 typedef struct {
110 DWORD version;
111 WORD ScriptList;
112 WORD FeatureList;
113 WORD LookupList;
114 } GSUB_Header;
116 typedef struct {
117 CHAR ScriptTag[4];
118 WORD Script;
119 } GSUB_ScriptRecord;
121 typedef struct {
122 WORD ScriptCount;
123 GSUB_ScriptRecord ScriptRecord[1];
124 } GSUB_ScriptList;
126 typedef struct {
127 CHAR LangSysTag[4];
128 WORD LangSys;
129 } GSUB_LangSysRecord;
131 typedef struct {
132 WORD DefaultLangSys;
133 WORD LangSysCount;
134 GSUB_LangSysRecord LangSysRecord[1];
135 } GSUB_Script;
137 typedef struct {
138 WORD LookupOrder; /* Reserved */
139 WORD ReqFeatureIndex;
140 WORD FeatureCount;
141 WORD FeatureIndex[1];
142 } GSUB_LangSys;
144 typedef struct {
145 CHAR FeatureTag[4];
146 WORD Feature;
147 } GSUB_FeatureRecord;
149 typedef struct {
150 WORD FeatureCount;
151 GSUB_FeatureRecord FeatureRecord[1];
152 } GSUB_FeatureList;
154 typedef struct {
155 WORD FeatureParams; /* Reserved */
156 WORD LookupCount;
157 WORD LookupListIndex[1];
158 } GSUB_Feature;
160 typedef struct {
161 WORD LookupCount;
162 WORD Lookup[1];
163 } GSUB_LookupList;
165 typedef struct {
166 WORD LookupType;
167 WORD LookupFlag;
168 WORD SubTableCount;
169 WORD SubTable[1];
170 } GSUB_LookupTable;
172 typedef struct {
173 WORD CoverageFormat;
174 WORD GlyphCount;
175 WORD GlyphArray[1];
176 } GSUB_CoverageFormat1;
178 typedef struct {
179 WORD Start;
180 WORD End;
181 WORD StartCoverageIndex;
182 } GSUB_RangeRecord;
184 typedef struct {
185 WORD CoverageFormat;
186 WORD RangeCount;
187 GSUB_RangeRecord RangeRecord[1];
188 } GSUB_CoverageFormat2;
190 typedef struct {
191 WORD SubstFormat; /* = 1 */
192 WORD Coverage;
193 WORD DeltaGlyphID;
194 } GSUB_SingleSubstFormat1;
196 typedef struct {
197 WORD SubstFormat; /* = 2 */
198 WORD Coverage;
199 WORD GlyphCount;
200 WORD Substitute[1];
201 }GSUB_SingleSubstFormat2;
203 typedef struct {
204 WORD SubstFormat; /* = 1 */
205 WORD Coverage;
206 WORD LigSetCount;
207 WORD LigatureSet[1];
208 }GSUB_LigatureSubstFormat1;
210 typedef struct {
211 WORD LigatureCount;
212 WORD Ligature[1];
213 }GSUB_LigatureSet;
215 typedef struct{
216 WORD LigGlyph;
217 WORD CompCount;
218 WORD Component[1];
219 }GSUB_Ligature;
221 typedef struct{
222 WORD SequenceIndex;
223 WORD LookupListIndex;
225 }GSUB_SubstLookupRecord;
227 typedef struct{
228 WORD SubstFormat; /* = 1 */
229 WORD Coverage;
230 WORD ChainSubRuleSetCount;
231 WORD ChainSubRuleSet[1];
232 }GSUB_ChainContextSubstFormat1;
234 typedef struct {
235 WORD SubstFormat; /* = 3 */
236 WORD BacktrackGlyphCount;
237 WORD Coverage[1];
238 }GSUB_ChainContextSubstFormat3_1;
240 typedef struct{
241 WORD InputGlyphCount;
242 WORD Coverage[1];
243 }GSUB_ChainContextSubstFormat3_2;
245 typedef struct{
246 WORD LookaheadGlyphCount;
247 WORD Coverage[1];
248 }GSUB_ChainContextSubstFormat3_3;
250 typedef struct{
251 WORD SubstCount;
252 GSUB_SubstLookupRecord SubstLookupRecord[1];
253 }GSUB_ChainContextSubstFormat3_4;
255 typedef struct {
256 WORD SubstFormat; /* = 1 */
257 WORD Coverage;
258 WORD AlternateSetCount;
259 WORD AlternateSet[1];
260 } GSUB_AlternateSubstFormat1;
262 typedef struct{
263 WORD GlyphCount;
264 WORD Alternate[1];
265 } GSUB_AlternateSet;
267 /* These are all structures needed for the GDEF table */
268 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
270 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
272 typedef struct {
273 DWORD Version;
274 WORD GlyphClassDef;
275 WORD AttachList;
276 WORD LigCaretList;
277 WORD MarkAttachClassDef;
278 } GDEF_Header;
280 typedef struct {
281 WORD ClassFormat;
282 WORD StartGlyph;
283 WORD GlyphCount;
284 WORD ClassValueArray[1];
285 } GDEF_ClassDefFormat1;
287 typedef struct {
288 WORD Start;
289 WORD End;
290 WORD Class;
291 } GDEF_ClassRangeRecord;
293 typedef struct {
294 WORD ClassFormat;
295 WORD ClassRangeCount;
296 GDEF_ClassRangeRecord ClassRangeRecord[1];
297 } GDEF_ClassDefFormat2;
299 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
301 typedef struct tagVowelComponents
303 WCHAR base;
304 WCHAR parts[3];
305 } VowelComponents;
307 typedef struct tagConsonantComponents
309 WCHAR parts[3];
310 WCHAR output;
311 } ConsonantComponents;
313 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
315 /* the orders of joined_forms and contextual_features need to line up */
316 static const char* contextual_features[] =
318 "isol",
319 "fina",
320 "init",
321 "medi",
322 /* Syriac Alaph */
323 "med2",
324 "fin2",
325 "fin3"
328 static OPENTYPE_FEATURE_RECORD standard_features[] =
330 { MS_MAKE_TAG('l','i','g','a'), 1},
331 { MS_MAKE_TAG('c','l','i','g'), 1},
334 static OPENTYPE_FEATURE_RECORD arabic_features[] =
336 { MS_MAKE_TAG('r','l','i','g'), 1},
337 { MS_MAKE_TAG('c','a','l','t'), 1},
338 { MS_MAKE_TAG('l','i','g','a'), 1},
339 { MS_MAKE_TAG('d','l','i','g'), 1},
340 { MS_MAKE_TAG('c','s','w','h'), 1},
341 { MS_MAKE_TAG('m','s','e','t'), 1},
344 static const char* required_arabic_features[] =
346 "fina",
347 "init",
348 "medi",
349 "rlig",
350 NULL
353 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
355 { MS_MAKE_TAG('d','l','i','g'), 1},
358 static OPENTYPE_FEATURE_RECORD syriac_features[] =
360 { MS_MAKE_TAG('r','l','i','g'), 1},
361 { MS_MAKE_TAG('c','a','l','t'), 1},
362 { MS_MAKE_TAG('l','i','g','a'), 1},
363 { MS_MAKE_TAG('d','l','i','g'), 1},
366 static const char* required_syriac_features[] =
368 "fina",
369 "fin2",
370 "fin3",
371 "init",
372 "medi",
373 "med2",
374 "rlig",
375 NULL
378 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
380 /* Presentation forms */
381 { MS_MAKE_TAG('b','l','w','s'), 1},
382 { MS_MAKE_TAG('a','b','v','s'), 1},
383 { MS_MAKE_TAG('p','s','t','s'), 1},
386 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
388 { MS_MAKE_TAG('a','b','v','s'), 1},
389 { MS_MAKE_TAG('b','l','w','s'), 1},
392 static OPENTYPE_FEATURE_RECORD thai_features[] =
394 { MS_MAKE_TAG('c','c','m','p'), 1},
397 static const char* required_lao_features[] =
399 "ccmp",
400 NULL
403 static const char* required_devanagari_features[] =
405 "nukt",
406 "akhn",
407 "rphf",
408 "blwf",
409 "half",
410 "vatu",
411 "pres",
412 "abvs",
413 "blws",
414 "psts",
415 "haln",
416 NULL
419 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
421 { MS_MAKE_TAG('p','r','e','s'), 1},
422 { MS_MAKE_TAG('a','b','v','s'), 1},
423 { MS_MAKE_TAG('b','l','w','s'), 1},
424 { MS_MAKE_TAG('p','s','t','s'), 1},
425 { MS_MAKE_TAG('h','a','l','n'), 1},
426 { MS_MAKE_TAG('c','a','l','t'), 1},
429 static const char* required_bengali_features[] =
431 "nukt",
432 "akhn",
433 "rphf",
434 "blwf",
435 "half",
436 "vatu",
437 "pstf",
438 "init",
439 "abvs",
440 "blws",
441 "psts",
442 "haln",
443 NULL
446 static const char* required_gurmukhi_features[] =
448 "nukt",
449 "akhn",
450 "rphf",
451 "blwf",
452 "half",
453 "pstf",
454 "vatu",
455 "cjct",
456 "pres",
457 "abvs",
458 "blws",
459 "psts",
460 "haln",
461 "calt",
462 NULL
465 static const char* required_oriya_features[] =
467 "nukt",
468 "akhn",
469 "rphf",
470 "blwf",
471 "pstf",
472 "cjct",
473 "pres",
474 "abvs",
475 "blws",
476 "psts",
477 "haln",
478 "calt",
479 NULL
482 static const char* required_tamil_features[] =
484 "nukt",
485 "akhn",
486 "rphf",
487 "pref",
488 "half",
489 "pres",
490 "abvs",
491 "blws",
492 "psts",
493 "haln",
494 "calt",
495 NULL
498 static const char* required_telugu_features[] =
500 "nukt",
501 "akhn",
502 "rphf",
503 "pref",
504 "half",
505 "pstf",
506 "cjct",
507 "pres",
508 "abvs",
509 "blws",
510 "psts",
511 "haln",
512 "calt",
513 NULL
516 typedef struct ScriptShapeDataTag {
517 TEXTRANGE_PROPERTIES defaultTextRange;
518 const char** requiredFeatures;
519 CHAR otTag[5];
520 CHAR newOtTag[5];
521 ContextualShapingProc contextProc;
522 ShapeCharGlyphPropProc charGlyphPropProc;
523 } ScriptShapeData;
525 /* in order of scripts */
526 static const ScriptShapeData ShapingData[] =
528 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
529 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
530 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
531 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
532 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
533 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
534 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
535 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
536 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
537 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
538 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
539 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
540 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
541 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
542 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
543 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
544 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
545 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
546 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
547 {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
548 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
549 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
550 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
551 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
552 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
553 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
554 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
555 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
556 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
557 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
558 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
559 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
560 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
561 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
562 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
563 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
564 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
565 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
566 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
567 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
568 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
569 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
570 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
571 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
574 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
576 const GSUB_CoverageFormat1* cf1;
578 cf1 = table;
580 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
582 int count = GET_BE_WORD(cf1->GlyphCount);
583 int i;
584 TRACE("Coverage Format 1, %i glyphs\n",count);
585 for (i = 0; i < count; i++)
586 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
587 return i;
588 return -1;
590 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
592 const GSUB_CoverageFormat2* cf2;
593 int i;
594 int count;
595 cf2 = (const GSUB_CoverageFormat2*)cf1;
597 count = GET_BE_WORD(cf2->RangeCount);
598 TRACE("Coverage Format 2, %i ranges\n",count);
599 for (i = 0; i < count; i++)
601 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
602 return -1;
603 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
604 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
606 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
607 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
610 return -1;
612 else
613 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
615 return -1;
618 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
620 const GSUB_ScriptList *script;
621 const GSUB_Script *deflt = NULL;
622 int i;
623 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
625 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
626 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
628 const GSUB_Script *scr;
629 int offset;
631 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
632 scr = (const GSUB_Script*)((const BYTE*)script + offset);
634 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
635 return scr;
636 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
637 deflt = scr;
639 return deflt;
642 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
644 int i;
645 int offset;
646 const GSUB_LangSys *Lang;
648 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
650 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
652 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
653 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
655 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
656 return Lang;
658 offset = GET_BE_WORD(script->DefaultLangSys);
659 if (offset)
661 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
662 return Lang;
664 return NULL;
667 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
669 int i;
670 const GSUB_FeatureList *feature;
671 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
673 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
674 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
676 int index = GET_BE_WORD(lang->FeatureIndex[i]);
677 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
679 const GSUB_Feature *feat;
680 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
681 return feat;
684 return NULL;
687 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
689 int j;
690 TRACE("Single Substitution Subtable\n");
692 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
694 int offset;
695 const GSUB_SingleSubstFormat1 *ssf1;
696 offset = GET_BE_WORD(look->SubTable[j]);
697 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
698 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
700 int offset = GET_BE_WORD(ssf1->Coverage);
701 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
702 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
704 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
705 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
706 TRACE(" 0x%x\n",glyphs[glyph_index]);
707 return glyph_index + 1;
710 else
712 const GSUB_SingleSubstFormat2 *ssf2;
713 INT index;
714 INT offset;
716 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
717 offset = GET_BE_WORD(ssf1->Coverage);
718 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
719 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
720 TRACE(" Coverage index %i\n",index);
721 if (index != -1)
723 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
724 return GSUB_E_NOGLYPH;
726 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
727 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
728 TRACE("0x%x\n",glyphs[glyph_index]);
729 return glyph_index + 1;
733 return GSUB_E_NOGLYPH;
736 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
738 int j;
739 TRACE("Alternate Substitution Subtable\n");
741 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
743 int offset;
744 const GSUB_AlternateSubstFormat1 *asf1;
745 INT index;
747 offset = GET_BE_WORD(look->SubTable[j]);
748 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
749 offset = GET_BE_WORD(asf1->Coverage);
751 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
752 if (index != -1)
754 const GSUB_AlternateSet *as;
755 offset = GET_BE_WORD(asf1->AlternateSet[index]);
756 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
757 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
758 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
759 return GSUB_E_NOGLYPH;
761 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
762 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
763 TRACE(" 0x%x\n",glyphs[glyph_index]);
764 return glyph_index + 1;
767 return GSUB_E_NOGLYPH;
770 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
772 int j;
774 TRACE("Ligature Substitution Subtable\n");
775 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
777 const GSUB_LigatureSubstFormat1 *lsf1;
778 int offset,index;
780 offset = GET_BE_WORD(look->SubTable[j]);
781 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
782 offset = GET_BE_WORD(lsf1->Coverage);
783 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
784 TRACE(" Coverage index %i\n",index);
785 if (index != -1)
787 const GSUB_LigatureSet *ls;
788 int k, count;
790 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
791 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
792 count = GET_BE_WORD(ls->LigatureCount);
793 TRACE(" LigatureSet has %i members\n",count);
794 for (k = 0; k < count; k++)
796 const GSUB_Ligature *lig;
797 int CompCount,l,CompIndex;
799 offset = GET_BE_WORD(ls->Ligature[k]);
800 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
801 CompCount = GET_BE_WORD(lig->CompCount) - 1;
802 CompIndex = glyph_index+write_dir;
803 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
805 int CompGlyph;
806 CompGlyph = GET_BE_WORD(lig->Component[l]);
807 if (CompGlyph != glyphs[CompIndex])
808 break;
809 CompIndex += write_dir;
811 if (l == CompCount)
813 int replaceIdx = glyph_index;
814 if (write_dir < 0)
815 replaceIdx = glyph_index - CompCount;
817 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
818 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
819 TRACE("0x%x\n",glyphs[replaceIdx]);
820 if (CompCount > 0)
822 int j;
823 for (j = replaceIdx + 1; j < *glyph_count; j++)
824 glyphs[j] =glyphs[j+CompCount];
825 *glyph_count = *glyph_count - CompCount;
827 return replaceIdx + 1;
832 return GSUB_E_NOGLYPH;
835 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
837 int j;
838 BOOL done = FALSE;
840 TRACE("Chaining Contextual Substitution Subtable\n");
841 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
843 const GSUB_ChainContextSubstFormat1 *ccsf1;
844 int offset;
845 int dirLookahead = write_dir;
846 int dirBacktrack = -1 * write_dir;
848 offset = GET_BE_WORD(look->SubTable[j]);
849 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
850 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
852 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
853 continue;
855 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
857 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
858 continue;
860 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
862 int k;
863 int indexGlyphs;
864 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
865 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
866 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
867 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
868 int newIndex = glyph_index;
870 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
872 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
874 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
876 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
877 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
878 break;
880 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
881 continue;
882 TRACE("Matched Backtrack\n");
884 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
886 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
887 for (k = 0; k < indexGlyphs; k++)
889 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
890 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
891 break;
893 if (k != indexGlyphs)
894 continue;
895 TRACE("Matched IndexGlyphs\n");
897 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
899 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
901 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
902 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
903 break;
905 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
906 continue;
907 TRACE("Matched LookAhead\n");
909 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
911 if (GET_BE_WORD(ccsf3_4->SubstCount))
913 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
915 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
916 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
918 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
919 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
920 if (newIndex == -1)
922 ERR("Chain failed to generate a glyph\n");
923 continue;
926 return newIndex;
928 else return GSUB_E_NOGLYPH;
931 return -1;
934 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
936 int offset;
937 const GSUB_LookupTable *look;
939 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
940 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
941 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
942 switch(GET_BE_WORD(look->LookupType))
944 case 1:
945 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
946 case 3:
947 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
948 case 4:
949 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
950 case 6:
951 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
952 default:
953 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
955 return GSUB_E_NOGLYPH;
958 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
960 int i;
961 int out_index = GSUB_E_NOGLYPH;
962 const GSUB_LookupList *lookup;
964 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
966 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
967 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
969 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
970 if (out_index != GSUB_E_NOGLYPH)
971 break;
973 if (out_index == GSUB_E_NOGLYPH)
974 TRACE("lookups found no glyphs\n");
975 else
977 int out2;
978 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
979 if (out2!=GSUB_E_NOGLYPH)
980 out_index = out2;
982 return out_index;
985 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
987 UINT charset;
989 if (psc->userScript != 0)
991 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
992 return ShapingData[psa->eScript].newOtTag;
993 else
994 return (char*)&psc->userScript;
997 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
998 return ShapingData[psa->eScript].newOtTag;
1000 if (ShapingData[psa->eScript].otTag[0] != 0)
1001 return ShapingData[psa->eScript].otTag;
1004 * fall back to the font charset
1006 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1007 switch (charset)
1009 case ANSI_CHARSET: return "latn";
1010 case BALTIC_CHARSET: return "latn"; /* ?? */
1011 case CHINESEBIG5_CHARSET: return "hani";
1012 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1013 case GB2312_CHARSET: return "hani";
1014 case GREEK_CHARSET: return "grek";
1015 case HANGUL_CHARSET: return "hang";
1016 case RUSSIAN_CHARSET: return "cyrl";
1017 case SHIFTJIS_CHARSET: return "kana";
1018 case TURKISH_CHARSET: return "latn"; /* ?? */
1019 case VIETNAMESE_CHARSET: return "latn";
1020 case JOHAB_CHARSET: return "latn"; /* ?? */
1021 case ARABIC_CHARSET: return "arab";
1022 case HEBREW_CHARSET: return "hebr";
1023 case THAI_CHARSET: return "thai";
1024 default: return "latn";
1028 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1030 const GSUB_Feature *feature;
1031 int i;
1033 for (i = 0; i < psc->feature_count; i++)
1034 if (strncmp(psc->features[i].tag,feat,4)==0)
1035 return psc->features[i].feature;
1037 feature = NULL;
1039 if (psc->GSUB_Table)
1041 const GSUB_Script *script;
1042 const GSUB_LangSys *language;
1043 int attempt = 2;
1047 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1048 attempt--;
1049 if (script)
1051 if (psc->userLang != 0)
1052 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1053 else
1054 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1055 if (language)
1056 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1058 } while(attempt && !feature);
1060 /* try in the default (latin) table */
1061 if (!feature)
1063 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1064 if (script)
1066 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1067 if (language)
1068 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1073 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1075 psc->feature_count++;
1077 if (psc->features)
1078 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1079 else
1080 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1082 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1083 psc->features[psc->feature_count - 1].feature = feature;
1084 return feature;
1087 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)
1089 const GSUB_Feature *feature;
1091 feature = load_GSUB_feature(hdc, psa, psc, feat);
1092 if (!feature)
1093 return GSUB_E_NOFEATURE;
1095 TRACE("applying feature %s\n",feat);
1096 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1099 static VOID *load_gsub_table(HDC hdc)
1101 VOID* GSUB_Table = NULL;
1102 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1103 if (length != GDI_ERROR)
1105 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1106 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1107 TRACE("Loaded GSUB table of %i bytes\n",length);
1109 return GSUB_Table;
1112 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)
1114 WORD *glyphs;
1115 INT glyph_count = count;
1116 INT rc;
1118 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1119 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1120 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1121 if (rc > GSUB_E_NOGLYPH)
1122 rc = count - glyph_count;
1123 else
1124 rc = 0;
1126 HeapFree(GetProcessHeap(),0,glyphs);
1127 return rc;
1130 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1132 int offset;
1133 WORD class = 0;
1134 const GDEF_ClassDefFormat1 *cf1;
1136 if (!header)
1137 return 0;
1139 offset = GET_BE_WORD(header->GlyphClassDef);
1140 if (!offset)
1141 return 0;
1143 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1144 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1146 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1148 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1149 if (index < GET_BE_WORD(cf1->GlyphCount))
1150 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1153 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1155 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1156 int i, top;
1157 top = GET_BE_WORD(cf2->ClassRangeCount);
1158 for (i = 0; i < top; i++)
1160 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1161 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1163 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1164 break;
1168 else
1169 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1171 return class;
1174 static VOID *load_gdef_table(HDC hdc)
1176 VOID* GDEF_Table = NULL;
1177 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1178 if (length != GDI_ERROR)
1180 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1181 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1182 TRACE("Loaded GDEF table of %i bytes\n",length);
1184 return GDEF_Table;
1187 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1189 int i;
1191 if (!psc->GDEF_Table)
1192 psc->GDEF_Table = load_gdef_table(hdc);
1194 for (i = 0; i < cGlyphs; i++)
1196 WORD class;
1198 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1200 switch (class)
1202 case 0:
1203 case BaseGlyph:
1204 pGlyphProp[i].sva.fClusterStart = 1;
1205 pGlyphProp[i].sva.fDiacritic = 0;
1206 pGlyphProp[i].sva.fZeroWidth = 0;
1207 break;
1208 case LigatureGlyph:
1209 pGlyphProp[i].sva.fClusterStart = 1;
1210 pGlyphProp[i].sva.fDiacritic = 0;
1211 pGlyphProp[i].sva.fZeroWidth = 0;
1212 break;
1213 case MarkGlyph:
1214 pGlyphProp[i].sva.fClusterStart = 0;
1215 pGlyphProp[i].sva.fDiacritic = 1;
1216 pGlyphProp[i].sva.fZeroWidth = 1;
1217 break;
1218 case ComponentGlyph:
1219 pGlyphProp[i].sva.fClusterStart = 0;
1220 pGlyphProp[i].sva.fDiacritic = 0;
1221 pGlyphProp[i].sva.fZeroWidth = 0;
1222 break;
1223 default:
1224 ERR("Unknown glyph class %i\n",class);
1225 pGlyphProp[i].sva.fClusterStart = 1;
1226 pGlyphProp[i].sva.fDiacritic = 0;
1227 pGlyphProp[i].sva.fZeroWidth = 0;
1232 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1234 int i;
1236 for (i = 0; i < cGlyphs; i++)
1238 if (!pGlyphProp[i].sva.fClusterStart)
1240 int j;
1241 for (j = 0; j < cChars; j++)
1243 if (pwLogClust[j] == i)
1245 int k = j;
1246 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1247 k-=1;
1248 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1249 pwLogClust[j] = pwLogClust[k];
1256 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1258 if (changeCount == 0)
1259 return;
1260 else
1262 int i;
1263 int target_glyph = nextIndex - 1;
1264 int target_index = -1;
1265 int replacing_glyph = -1;
1266 int changed = 0;
1268 if (write_dir > 0)
1269 for (i = 0; i < chars; i++)
1271 if (pwLogClust[i] == target_glyph)
1273 target_index = i;
1274 break;
1277 else
1278 for (i = chars - 1; i >= 0; i--)
1280 if (pwLogClust[i] == target_glyph)
1282 target_index = i;
1283 break;
1286 if (target_index == -1)
1288 ERR("Unable to find target glyph\n");
1289 return;
1292 if (changeCount < 0)
1294 /* merge glyphs */
1295 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1297 if (pwLogClust[i] == target_glyph)
1298 continue;
1299 if(pwLogClust[i] == replacing_glyph)
1300 pwLogClust[i] = target_glyph;
1301 else
1303 changed--;
1304 if (changed >= changeCount)
1306 replacing_glyph = pwLogClust[i];
1307 pwLogClust[i] = target_glyph;
1309 else
1310 break;
1315 /* renumber trailing indexes*/
1316 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1318 if (pwLogClust[i] != target_glyph)
1319 pwLogClust[i] += changeCount;
1324 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 )
1326 int i;
1328 if (psc->GSUB_Table)
1330 const GSUB_Feature *feature;
1332 feature = load_GSUB_feature(hdc, psa, psc, feat);
1333 if (!feature)
1334 return GSUB_E_NOFEATURE;
1336 i = 0;
1337 TRACE("applying feature %s\n",debugstr_an(feat,4));
1338 while(i < *pcGlyphs)
1340 INT nextIndex;
1341 INT prevCount = *pcGlyphs;
1342 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1343 if (nextIndex > GSUB_E_NOGLYPH)
1345 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1346 i = nextIndex;
1348 else
1349 i++;
1351 return *pcGlyphs;
1353 return GSUB_E_NOFEATURE;
1356 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1358 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1361 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1363 if (i + delta < 0)
1364 return 0;
1365 if ( i+ delta >= cchLen)
1366 return 0;
1368 i += delta;
1370 return chars[i];
1373 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1375 if (i + delta < 0)
1377 if (psa->fLinkBefore)
1378 return jtR;
1379 else
1380 return jtU;
1382 if ( i+ delta >= cchLen)
1384 if (psa->fLinkAfter)
1385 return jtL;
1386 else
1387 return jtU;
1390 i += delta;
1392 if (context_type[i] == jtT)
1393 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1394 else
1395 return context_type[i];
1398 static inline BOOL right_join_causing(CHAR joining_type)
1400 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1403 static inline BOOL left_join_causing(CHAR joining_type)
1405 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1408 static inline BOOL word_break_causing(WCHAR chr)
1410 /* we are working within a string of characters already guareented to
1411 be within one script, Syriac, so we do not worry about any character
1412 other than the space character outside of that range */
1413 return (chr == 0 || chr == 0x20 );
1417 * ContextualShape_Arabic
1419 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1421 CHAR *context_type;
1422 INT *context_shape;
1423 INT dirR, dirL;
1424 int i;
1426 if (*pcGlyphs != cChars)
1428 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1429 return;
1432 if (!psa->fLogicalOrder && psa->fRTL)
1434 dirR = 1;
1435 dirL = -1;
1437 else
1439 dirR = -1;
1440 dirL = 1;
1443 if (!psc->GSUB_Table)
1444 psc->GSUB_Table = load_gsub_table(hdc);
1446 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1447 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1449 for (i = 0; i < cChars; i++)
1450 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1452 for (i = 0; i < cChars; i++)
1454 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1455 context_shape[i] = Xr;
1456 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1457 context_shape[i] = Xl;
1458 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)))
1459 context_shape[i] = Xm;
1460 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1461 context_shape[i] = Xr;
1462 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1463 context_shape[i] = Xl;
1464 else
1465 context_shape[i] = Xn;
1468 /* Contextual Shaping */
1469 i = 0;
1470 while(i < *pcGlyphs)
1472 BOOL shaped = FALSE;
1474 if (psc->GSUB_Table)
1476 INT nextIndex;
1477 INT prevCount = *pcGlyphs;
1478 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1479 if (nextIndex > GSUB_E_NOGLYPH)
1481 i = nextIndex;
1482 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1484 shaped = (nextIndex > GSUB_E_NOGLYPH);
1487 if (!shaped)
1489 WORD newGlyph = pwOutGlyphs[i];
1490 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1492 /* fall back to presentation form B */
1493 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1494 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1495 pwOutGlyphs[i] = newGlyph;
1497 i++;
1501 HeapFree(GetProcessHeap(),0,context_shape);
1502 HeapFree(GetProcessHeap(),0,context_type);
1506 * ContextualShape_Syriac
1509 #define ALAPH 0x710
1510 #define DALATH 0x715
1511 #define RISH 0x72A
1513 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1515 CHAR *context_type;
1516 INT *context_shape;
1517 INT dirR, dirL;
1518 int i;
1520 if (*pcGlyphs != cChars)
1522 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1523 return;
1526 if (!psa->fLogicalOrder && psa->fRTL)
1528 dirR = 1;
1529 dirL = -1;
1531 else
1533 dirR = -1;
1534 dirL = 1;
1537 if (!psc->GSUB_Table)
1538 psc->GSUB_Table = load_gsub_table(hdc);
1540 if (!psc->GSUB_Table)
1541 return;
1543 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1544 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1546 for (i = 0; i < cChars; i++)
1547 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1549 for (i = 0; i < cChars; i++)
1551 if (pwcChars[i] == ALAPH)
1553 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1555 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1556 context_shape[i] = Afj;
1557 else if ( rchar != DALATH && rchar != RISH &&
1558 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1559 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1560 context_shape[i] = Afn;
1561 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1562 context_shape[i] = Afx;
1563 else
1564 context_shape[i] = Xn;
1566 else if (context_type[i] == jtR &&
1567 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1568 context_shape[i] = Xr;
1569 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1570 context_shape[i] = Xl;
1571 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)))
1572 context_shape[i] = Xm;
1573 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1574 context_shape[i] = Xr;
1575 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1576 context_shape[i] = Xl;
1577 else
1578 context_shape[i] = Xn;
1581 /* Contextual Shaping */
1582 i = 0;
1583 while(i < *pcGlyphs)
1585 INT nextIndex;
1586 INT prevCount = *pcGlyphs;
1587 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1588 if (nextIndex > GSUB_E_NOGLYPH)
1590 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1591 i = nextIndex;
1593 else
1594 i++;
1597 HeapFree(GetProcessHeap(),0,context_shape);
1598 HeapFree(GetProcessHeap(),0,context_type);
1602 * ContextualShape_Phags_pa
1605 #define phags_pa_CANDRABINDU 0xA873
1606 #define phags_pa_START 0xA840
1607 #define phags_pa_END 0xA87F
1609 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1611 INT *context_shape;
1612 INT dirR, dirL;
1613 int i;
1615 if (*pcGlyphs != cChars)
1617 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1618 return;
1621 if (!psa->fLogicalOrder && psa->fRTL)
1623 dirR = 1;
1624 dirL = -1;
1626 else
1628 dirR = -1;
1629 dirL = 1;
1632 if (!psc->GSUB_Table)
1633 psc->GSUB_Table = load_gsub_table(hdc);
1635 if (!psc->GSUB_Table)
1636 return;
1638 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1640 for (i = 0; i < cChars; i++)
1642 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1644 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1645 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1646 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1647 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1649 if (jrchar && jlchar)
1650 context_shape[i] = Xm;
1651 else if (jrchar)
1652 context_shape[i] = Xr;
1653 else if (jlchar)
1654 context_shape[i] = Xl;
1655 else
1656 context_shape[i] = Xn;
1658 else
1659 context_shape[i] = -1;
1662 /* Contextual Shaping */
1663 i = 0;
1664 while(i < *pcGlyphs)
1666 if (context_shape[i] >= 0)
1668 INT nextIndex;
1669 INT prevCount = *pcGlyphs;
1670 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1671 if (nextIndex > GSUB_E_NOGLYPH)
1673 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1674 i = nextIndex;
1676 else
1677 i++;
1679 else
1680 i++;
1683 HeapFree(GetProcessHeap(),0,context_shape);
1686 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1688 int i;
1690 /* Replace */
1691 pwOutChars[cWalk] = replacements[0];
1692 cWalk=cWalk+1;
1694 /* Insert */
1695 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1697 int j;
1698 for (j = *pcChars; j > cWalk; j--)
1699 pwOutChars[j] = pwOutChars[j-1];
1700 *pcChars= *pcChars+1;
1701 pwOutChars[cWalk] = replacements[i];
1702 cWalk = cWalk+1;
1706 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1708 int i;
1709 int cWalk;
1711 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1713 for (i = 0; vowels[i].base != 0x0; i++)
1715 if (pwOutChars[cWalk] == vowels[i].base)
1717 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1718 if (vowels[i].parts[1]) cWalk++;
1719 if (vowels[i].parts[2]) cWalk++;
1720 break;
1726 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1728 int i;
1729 int cWalk;
1731 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1733 for (i = 0; consonants[i].output!= 0x0; i++)
1735 int j;
1736 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1737 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1738 break;
1740 if (consonants[i].parts[j]==0x0) /* matched all */
1742 int k;
1743 j--;
1744 pwOutChars[cWalk] = consonants[i].output;
1745 for(k = cWalk+1; k < *pcChars - j; k++)
1746 pwOutChars[k] = pwOutChars[k+j];
1747 *pcChars = *pcChars - j;
1748 break;
1751 cWalk++;
1755 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1757 if (s->ralf >= 0)
1759 int j;
1760 WORD Ra = pwChar[s->start];
1761 WORD H = pwChar[s->start+1];
1763 TRACE("Doing reorder of Ra to %i\n",s->base);
1764 for (j = s->start; j < s->base-1; j++)
1765 pwChar[j] = pwChar[j+2];
1766 pwChar[s->base-1] = Ra;
1767 pwChar[s->base] = H;
1769 s->ralf = s->base-1;
1770 s->base -= 2;
1774 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1776 if (s->ralf >= 0)
1778 int j,loc;
1779 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1780 WORD Ra = pwChar[s->start];
1781 WORD H = pwChar[s->start+1];
1782 for (loc = s->end; loc > stop; loc--)
1783 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1784 break;
1786 TRACE("Doing reorder of Ra to %i\n",loc);
1787 for (j = s->start; j < loc-1; j++)
1788 pwChar[j] = pwChar[j+2];
1789 pwChar[loc-1] = Ra;
1790 pwChar[loc] = H;
1792 s->ralf = loc-1;
1793 s->base -= 2;
1794 if (s->blwf >= 0) s->blwf -= 2;
1795 if (s->pref >= 0) s->pref -= 2;
1799 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1801 if (s->ralf >= 0)
1803 int j;
1804 WORD Ra = pwChar[s->start];
1805 WORD H = pwChar[s->start+1];
1807 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1808 for (j = s->start; j < s->end-1; j++)
1809 pwChar[j] = pwChar[j+2];
1810 pwChar[s->end-1] = Ra;
1811 pwChar[s->end] = H;
1813 s->ralf = s->end-1;
1814 s->base -= 2;
1815 if (s->blwf >= 0) s->blwf -= 2;
1816 if (s->pref >= 0) s->pref -= 2;
1820 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1822 int i;
1824 /* reorder Matras */
1825 if (s->end > s->base)
1827 for (i = 1; i <= s->end-s->base; i++)
1829 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1831 int j;
1832 WCHAR c = pwChar[s->base+i];
1833 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1834 for (j = s->base+i; j > s->base; j--)
1835 pwChar[j] = pwChar[j-1];
1836 pwChar[s->base] = c;
1838 if (s->ralf >= s->base) s->ralf++;
1839 if (s->blwf >= s->base) s->blwf++;
1840 if (s->pref >= s->base) s->pref++;
1841 s->base ++;
1847 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1849 int i;
1851 /* reorder Matras */
1852 if (s->end > s->base)
1854 for (i = 1; i <= s->end-s->base; i++)
1856 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1858 int j;
1859 WCHAR c = pwChar[s->base+i];
1860 TRACE("Doing reorder of %x to %i\n",c,s->start);
1861 for (j = s->base+i; j > s->start; j--)
1862 pwChar[j] = pwChar[j-1];
1863 pwChar[s->start] = c;
1865 if (s->ralf >= 0) s->ralf++;
1866 if (s->blwf >= 0) s->blwf++;
1867 if (s->pref >= 0) s->pref++;
1868 s->base ++;
1874 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1876 if (s->blwf >= 0 && g->blwf > g->base)
1878 int j,loc;
1879 int g_offset;
1880 for (loc = s->end; loc > s->blwf; loc--)
1881 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1882 break;
1884 g_offset = (loc - s->blwf) - 1;
1886 if (loc != s->blwf)
1888 WORD blwf = glyphs[g->blwf];
1889 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1890 /* do not care about the pwChar array anymore, just the glyphs */
1891 for (j = 0; j < g_offset; j++)
1892 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1893 glyphs[g->blwf + g_offset] = blwf;
1898 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1900 int i;
1902 /* reorder previously moved Matras to correct position*/
1903 for (i = s->start; i < s->base; i++)
1905 if (lexical(pwChar[i]) == lex_Matra_pre)
1907 int j;
1908 int g_start = g->start + i - s->start;
1909 if (g_start < g->base -1 )
1911 WCHAR og = glyphs[g_start];
1912 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1913 for (j = g_start; j < g->base-1; j++)
1914 glyphs[j] = glyphs[j+1];
1915 glyphs[g->base-1] = og;
1921 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1923 if (s->pref >= 0 && g->pref > g->base)
1925 int j;
1926 WCHAR og = glyphs[g->pref];
1927 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1928 for (j = g->pref; j > g->base; j--)
1929 glyphs[j] = glyphs[j-1];
1930 glyphs[g->base] = og;
1934 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1936 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1937 if (s->start == s->base && s->base == s->end) return;
1938 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1940 Reorder_Ra_follows_base(pwChar, s, lexical);
1941 Reorder_Matra_precede_base(pwChar, s, lexical);
1944 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1946 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1947 if (s->start == s->base && s->base == s->end) return;
1948 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1950 Reorder_Ra_follows_matra(pwChar, s, lexical);
1951 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1954 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1956 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1957 if (s->start == s->base && s->base == s->end) return;
1958 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1960 Reorder_Ra_follows_base(pwChar, s, lexical);
1961 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1964 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1966 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1967 if (s->start == s->base && s->base == s->end) return;
1968 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1970 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1971 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1974 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1976 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1977 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1978 if (s->start == s->base && s->base == s->end) return;
1979 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1981 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1984 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1986 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1987 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1988 if (s->start == s->base && s->base == s->end) return;
1989 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1991 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1992 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1996 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1998 if (shift == 0)
1999 return;
2001 if (glyph_index->start > index)
2002 glyph_index->start += shift;
2003 if (glyph_index->base > index)
2004 glyph_index->base+= shift;
2005 if (glyph_index->end > index)
2006 glyph_index->end+= shift;
2007 if (glyph_index->ralf > index)
2008 glyph_index->ralf+= shift;
2009 if (glyph_index->blwf > index)
2010 glyph_index->blwf+= shift;
2011 if (glyph_index->pref > index)
2012 glyph_index->pref+= shift;
2015 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 )
2017 int index = glyph_index->start;
2019 if (!feature)
2020 return;
2022 while(index <= glyph_index->end)
2024 INT nextIndex;
2025 INT prevCount = *pcGlyphs;
2026 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2027 if (nextIndex > GSUB_E_NOGLYPH)
2029 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2030 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2031 index = nextIndex;
2033 else
2034 index++;
2038 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2040 int i = 0;
2041 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)))))
2042 i++;
2043 if (index + i <= end-1)
2044 return index + i;
2045 else
2046 return -1;
2049 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)
2051 INT index, nextIndex;
2052 INT count,g_offset;
2054 count = syllable->base - syllable->start;
2056 g_offset = 0;
2057 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2058 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2060 INT prevCount = *pcGlyphs;
2061 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2062 if (nextIndex > GSUB_E_NOGLYPH)
2064 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2065 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2066 g_offset += (*pcGlyphs - prevCount);
2069 index+=2;
2070 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2074 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)
2076 INT nextIndex;
2077 INT prevCount = *pcGlyphs;
2079 if (syllable->ralf >= 0)
2081 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2082 if (nextIndex > GSUB_E_NOGLYPH)
2084 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2085 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2090 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2092 int i = 0;
2093 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2094 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2095 is_consonant(lexical(pwChars[index+i+1])))))
2096 i++;
2097 if (index + i <= end-1)
2098 return index+i;
2099 else
2100 return -1;
2103 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)
2105 INT index, nextIndex;
2106 INT count, g_offset=0;
2107 INT ralf = syllable->ralf;
2109 count = syllable->end - syllable->base;
2111 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2113 while (index >= 0)
2115 INT prevCount = *pcGlyphs;
2116 if (ralf >=0 && ralf < index)
2118 g_offset--;
2119 ralf = -1;
2122 if (!modern)
2124 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2125 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2126 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2129 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2130 if (nextIndex > GSUB_E_NOGLYPH)
2132 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2133 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2134 g_offset += (*pcGlyphs - prevCount);
2136 else if (!modern)
2138 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2139 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2140 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2143 index+=2;
2144 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2148 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)
2150 int c;
2151 int overall_shift = 0;
2152 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2153 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2154 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2155 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2156 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2157 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2158 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2159 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2160 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2161 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2162 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2163 IndicSyllable glyph_indexs;
2165 for (c = 0; c < syllable_count; c++)
2167 int old_end;
2168 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2169 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2170 old_end = glyph_indexs.end;
2172 if (locl)
2174 TRACE("applying feature locl\n");
2175 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2177 if (nukt)
2179 TRACE("applying feature nukt\n");
2180 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2182 if (akhn)
2184 TRACE("applying feature akhn\n");
2185 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2188 if (rphf)
2189 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2190 if (rkrf)
2192 TRACE("applying feature rkrf\n");
2193 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2195 if (pref)
2196 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2197 if (blwf)
2199 if (!modern)
2200 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2202 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2205 if (half)
2206 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2207 if (pstf)
2209 TRACE("applying feature pstf\n");
2210 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2212 if (vatu)
2214 TRACE("applying feature vatu\n");
2215 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2217 if (cjct)
2219 TRACE("applying feature cjct\n");
2220 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2223 if (second_reorder)
2224 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2226 overall_shift += glyph_indexs.end - old_end;
2230 static inline int unicode_lex(WCHAR c)
2232 int type;
2234 if (!c) return lex_Generic;
2235 if (c == 0x200D) return lex_ZWJ;
2236 if (c == 0x200C) return lex_ZWNJ;
2237 if (c == 0x00A0) return lex_NBSP;
2239 type = get_table_entry( indic_syllabic_table, c );
2241 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2243 switch( type )
2245 case 0x0d07: /* Unknown */
2246 case 0x0e07: /* Unknwon */
2247 default: return lex_Generic;
2248 case 0x0001:
2249 case 0x0002:
2250 case 0x0011:
2251 case 0x0012:
2252 case 0x0013:
2253 case 0x0014: return lex_Modifier;
2254 case 0x0003:
2255 case 0x0009:
2256 case 0x000a:
2257 case 0x000b:
2258 case 0x000d:
2259 case 0x000e:
2260 case 0x000f:
2261 case 0x0010: return lex_Consonant;
2262 case 0x0004: return lex_Nukta;
2263 case 0x0005: return lex_Halant;
2264 case 0x0006:
2265 case 0x0008: return lex_Vowel;
2266 case 0x0007:
2267 case 0x0107: return lex_Matra_post;
2268 case 0x0207:
2269 case 0x0307: return lex_Matra_pre;
2270 case 0x0807:
2271 case 0x0907:
2272 case 0x0a07:
2273 case 0x0b07:
2274 case 0x0c07:
2275 case 0x0407: return lex_Composed_Vowel;
2276 case 0x0507: return lex_Matra_above;
2277 case 0x0607: return lex_Matra_below;
2278 case 0x000c: return lex_Ra;
2282 static int sinhala_lex(WCHAR c)
2284 switch (c)
2286 case 0x0DDA:
2287 case 0x0DDD:
2288 case 0x0DDC:
2289 case 0x0DDE: return lex_Matra_post;
2290 default:
2291 return unicode_lex(c);
2295 static const VowelComponents Sinhala_vowels[] = {
2296 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2297 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2298 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2299 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2300 {0x0000, {0x0000,0x0000,0x0}}};
2302 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2304 int cCount = cChars;
2305 int i;
2306 WCHAR *input;
2307 IndicSyllable *syllables = NULL;
2308 int syllable_count = 0;
2310 if (*pcGlyphs != cChars)
2312 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2313 return;
2316 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2318 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2320 /* Step 1: Decompose multi part vowels */
2321 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels);
2323 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2325 /* Step 2: Reorder within Syllables */
2326 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2327 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2329 /* Step 3: Strip dangling joiners */
2330 for (i = 0; i < cCount; i++)
2332 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2333 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2334 input[i] = 0x0020;
2337 /* Step 4: Base Form application to syllables */
2338 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2339 *pcGlyphs = cCount;
2340 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2342 HeapFree(GetProcessHeap(),0,input);
2343 HeapFree(GetProcessHeap(),0,syllables);
2346 static int devanagari_lex(WCHAR c)
2348 switch (c)
2350 case 0x0930: return lex_Ra;
2351 default:
2352 return unicode_lex(c);
2356 static const ConsonantComponents Devanagari_consonants[] ={
2357 {{0x0928, 0x093C, 0x00000}, 0x0929},
2358 {{0x0930, 0x093C, 0x00000}, 0x0931},
2359 {{0x0933, 0x093C, 0x00000}, 0x0934},
2360 {{0x0915, 0x093C, 0x00000}, 0x0958},
2361 {{0x0916, 0x093C, 0x00000}, 0x0959},
2362 {{0x0917, 0x093C, 0x00000}, 0x095A},
2363 {{0x091C, 0x093C, 0x00000}, 0x095B},
2364 {{0x0921, 0x093C, 0x00000}, 0x095C},
2365 {{0x0922, 0x093C, 0x00000}, 0x095D},
2366 {{0x092B, 0x093C, 0x00000}, 0x095E},
2367 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2369 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2371 int cCount = cChars;
2372 WCHAR *input;
2373 IndicSyllable *syllables = NULL;
2374 int syllable_count = 0;
2375 BOOL modern = get_GSUB_Indic2(psa, psc);
2377 if (*pcGlyphs != cChars)
2379 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2380 return;
2383 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2384 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2386 /* Step 1: Compose Consonant and Nukta */
2387 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2388 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2390 /* Step 2: Reorder within Syllables */
2391 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2392 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2393 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2394 *pcGlyphs = cCount;
2396 /* Step 3: Base Form application to syllables */
2397 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2399 HeapFree(GetProcessHeap(),0,input);
2400 HeapFree(GetProcessHeap(),0,syllables);
2403 static int bengali_lex(WCHAR c)
2405 switch (c)
2407 case 0x09B0: return lex_Ra;
2408 default:
2409 return unicode_lex(c);
2413 static const VowelComponents Bengali_vowels[] = {
2414 {0x09CB, {0x09C7,0x09BE,0x0000}},
2415 {0x09CC, {0x09C7,0x09D7,0x0000}},
2416 {0x0000, {0x0000,0x0000,0x0000}}};
2418 static const ConsonantComponents Bengali_consonants[] = {
2419 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2420 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2421 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2422 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2423 {{0x0000,0x0000,0x0000}, 0x0000}};
2425 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2427 int cCount = cChars;
2428 WCHAR *input;
2429 IndicSyllable *syllables = NULL;
2430 int syllable_count = 0;
2431 BOOL modern = get_GSUB_Indic2(psa, psc);
2433 if (*pcGlyphs != cChars)
2435 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2436 return;
2439 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2440 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2442 /* Step 1: Decompose Vowels and Compose Consonents */
2443 DecomposeVowels(hdc, input, &cCount, Bengali_vowels);
2444 ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2445 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2447 /* Step 2: Reorder within Syllables */
2448 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2449 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2450 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2451 *pcGlyphs = cCount;
2453 /* Step 3: Initial form is only applied to the beginning of words */
2454 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2456 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2458 int index = cCount;
2459 int gCount = 1;
2460 if (index > 0) index++;
2462 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2466 /* Step 4: Base Form application to syllables */
2467 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2469 HeapFree(GetProcessHeap(),0,input);
2470 HeapFree(GetProcessHeap(),0,syllables);
2473 static int gurmukhi_lex(WCHAR c)
2475 return unicode_lex(c);
2478 static const ConsonantComponents Gurmukhi_consonants[] = {
2479 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2480 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2481 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2482 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2483 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2484 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2485 {{0x0000,0x0000,0x0000}, 0x0000}};
2487 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2489 int cCount = cChars;
2490 WCHAR *input;
2491 IndicSyllable *syllables = NULL;
2492 int syllable_count = 0;
2493 BOOL modern = get_GSUB_Indic2(psa, psc);
2495 if (*pcGlyphs != cChars)
2497 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2498 return;
2501 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2502 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2504 /* Step 1: Compose Consonents */
2505 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2506 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2508 /* Step 2: Reorder within Syllables */
2509 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2510 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2511 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2512 *pcGlyphs = cCount;
2514 /* Step 3: Base Form application to syllables */
2515 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2517 HeapFree(GetProcessHeap(),0,input);
2518 HeapFree(GetProcessHeap(),0,syllables);
2521 static int gujarati_lex(WCHAR c)
2523 switch (c)
2525 case 0x0AB0: return lex_Ra;
2526 default:
2527 return unicode_lex(c);
2531 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2533 int cCount = cChars;
2534 WCHAR *input;
2535 IndicSyllable *syllables = NULL;
2536 int syllable_count = 0;
2537 BOOL modern = get_GSUB_Indic2(psa, psc);
2539 if (*pcGlyphs != cChars)
2541 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2542 return;
2545 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2546 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2548 /* Step 1: Reorder within Syllables */
2549 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2550 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2551 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2552 *pcGlyphs = cCount;
2554 /* Step 2: Base Form application to syllables */
2555 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2557 HeapFree(GetProcessHeap(),0,input);
2558 HeapFree(GetProcessHeap(),0,syllables);
2561 static int oriya_lex(WCHAR c)
2563 switch (c)
2565 case 0x0B30: return lex_Ra;
2566 default:
2567 return unicode_lex(c);
2571 static const VowelComponents Oriya_vowels[] = {
2572 {0x0B48, {0x0B47,0x0B56,0x0000}},
2573 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2574 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2575 {0x0000, {0x0000,0x0000,0x0000}}};
2577 static const ConsonantComponents Oriya_consonants[] = {
2578 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2579 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2580 {{0x0000,0x0000,0x0000}, 0x0000}};
2582 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2584 int cCount = cChars;
2585 WCHAR *input;
2586 IndicSyllable *syllables = NULL;
2587 int syllable_count = 0;
2588 BOOL modern = get_GSUB_Indic2(psa, psc);
2590 if (*pcGlyphs != cChars)
2592 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2593 return;
2596 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2597 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2599 /* Step 1: Decompose Vowels and Compose Consonents */
2600 DecomposeVowels(hdc, input, &cCount, Oriya_vowels);
2601 ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2602 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2604 /* Step 2: Reorder within Syllables */
2605 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2606 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2607 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2608 *pcGlyphs = cCount;
2610 /* Step 3: Base Form application to syllables */
2611 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2613 HeapFree(GetProcessHeap(),0,input);
2614 HeapFree(GetProcessHeap(),0,syllables);
2617 static int tamil_lex(WCHAR c)
2619 return unicode_lex(c);
2622 static const VowelComponents Tamil_vowels[] = {
2623 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2624 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2625 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2626 {0x0000, {0x0000,0x0000,0x0000}}};
2628 static const ConsonantComponents Tamil_consonants[] = {
2629 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2630 {{0x0000,0x0000,0x0000}, 0x0000}};
2632 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2634 int cCount = cChars;
2635 WCHAR *input;
2636 IndicSyllable *syllables = NULL;
2637 int syllable_count = 0;
2638 BOOL modern = get_GSUB_Indic2(psa, psc);
2640 if (*pcGlyphs != cChars)
2642 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2643 return;
2646 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2647 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2649 /* Step 1: Decompose Vowels and Compose Consonents */
2650 DecomposeVowels(hdc, input, &cCount, Tamil_vowels);
2651 ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2652 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2654 /* Step 2: Reorder within Syllables */
2655 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2656 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2657 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2658 *pcGlyphs = cCount;
2660 /* Step 3: Base Form application to syllables */
2661 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2663 HeapFree(GetProcessHeap(),0,input);
2664 HeapFree(GetProcessHeap(),0,syllables);
2667 static int telugu_lex(WCHAR c)
2669 switch (c)
2671 case 0x0C43:
2672 case 0x0C44: return lex_Modifier;
2673 default:
2674 return unicode_lex(c);
2678 static const VowelComponents Telugu_vowels[] = {
2679 {0x0C48, {0x0C46,0x0C56,0x0000}},
2680 {0x0000, {0x0000,0x0000,0x0000}}};
2682 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2684 int cCount = cChars;
2685 WCHAR *input;
2686 IndicSyllable *syllables = NULL;
2687 int syllable_count = 0;
2688 BOOL modern = get_GSUB_Indic2(psa, psc);
2690 if (*pcGlyphs != cChars)
2692 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2693 return;
2696 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2697 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2699 /* Step 1: Decompose Vowels */
2700 DecomposeVowels(hdc, input, &cCount, Telugu_vowels);
2701 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2703 /* Step 2: Reorder within Syllables */
2704 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2705 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2706 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2707 *pcGlyphs = cCount;
2709 /* Step 3: Base Form application to syllables */
2710 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2712 HeapFree(GetProcessHeap(),0,input);
2713 HeapFree(GetProcessHeap(),0,syllables);
2716 static int kannada_lex(WCHAR c)
2718 switch (c)
2720 case 0x0CB0: return lex_Ra;
2721 default:
2722 return unicode_lex(c);
2726 static const VowelComponents Kannada_vowels[] = {
2727 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2728 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2729 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2730 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2731 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2732 {0x0000, {0x0000,0x0000,0x0000}}};
2734 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2736 int cCount = cChars;
2737 WCHAR *input;
2738 IndicSyllable *syllables = NULL;
2739 int syllable_count = 0;
2740 BOOL modern = get_GSUB_Indic2(psa, psc);
2742 if (*pcGlyphs != cChars)
2744 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2745 return;
2748 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2749 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2751 /* Step 1: Decompose Vowels */
2752 DecomposeVowels(hdc, input, &cCount, Kannada_vowels);
2753 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2755 /* Step 2: Reorder within Syllables */
2756 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2757 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2758 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2759 *pcGlyphs = cCount;
2761 /* Step 3: Base Form application to syllables */
2762 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2764 HeapFree(GetProcessHeap(),0,input);
2765 HeapFree(GetProcessHeap(),0,syllables);
2768 static int malayalam_lex(WCHAR c)
2770 return unicode_lex(c);
2773 static const VowelComponents Malayalam_vowels[] = {
2774 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2775 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2776 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2777 {0x0000, {0x0000,0x0000,0x0000}}};
2779 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2781 int cCount = cChars;
2782 WCHAR *input;
2783 IndicSyllable *syllables = NULL;
2784 int syllable_count = 0;
2785 BOOL modern = get_GSUB_Indic2(psa, psc);
2787 if (*pcGlyphs != cChars)
2789 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2790 return;
2793 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2794 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2796 /* Step 1: Decompose Vowels */
2797 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels);
2798 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2800 /* Step 2: Reorder within Syllables */
2801 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2802 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2803 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2804 *pcGlyphs = cCount;
2806 /* Step 3: Base Form application to syllables */
2807 ShapeIndicSyllables(hdc, psc, psa, input, cCount, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2809 HeapFree(GetProcessHeap(),0,input);
2810 HeapFree(GetProcessHeap(),0,syllables);
2813 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)
2815 int i,k;
2817 for (i = 0; i < cGlyphs; i++)
2819 int char_index[20];
2820 int char_count = 0;
2822 for (k = 0; k < cChars; k++)
2824 if (pwLogClust[k] == i)
2826 char_index[char_count] = k;
2827 char_count++;
2831 if (char_count == 0)
2833 FIXME("No chars in this glyph? Must be an error\n");
2834 continue;
2837 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2839 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2840 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2842 else
2843 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2846 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2847 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2850 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 )
2852 int i,k;
2853 int initGlyph, finaGlyph;
2854 INT dirR, dirL;
2855 BYTE *spaces;
2857 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2858 memset(spaces,0,cGlyphs);
2860 if (!psa->fLogicalOrder && psa->fRTL)
2862 initGlyph = cGlyphs-1;
2863 finaGlyph = 0;
2864 dirR = 1;
2865 dirL = -1;
2867 else
2869 initGlyph = 0;
2870 finaGlyph = cGlyphs-1;
2871 dirR = -1;
2872 dirL = 1;
2875 for (i = 0; i < cGlyphs; i++)
2877 for (k = 0; k < cChars; k++)
2878 if (pwLogClust[k] == i)
2880 if (pwcChars[k] == 0x0020)
2881 spaces[i] = 1;
2885 for (i = 0; i < cGlyphs; i++)
2887 int char_index[20];
2888 int char_count = 0;
2889 BOOL isInit, isFinal;
2891 for (k = 0; k < cChars; k++)
2893 if (pwLogClust[k] == i)
2895 char_index[char_count] = k;
2896 char_count++;
2900 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2901 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2903 if (char_count == 0)
2905 FIXME("No chars in this glyph? Must be an error\n");
2906 continue;
2909 if (char_count == 1)
2911 if (pwcChars[char_index[0]] == 0x0020) /* space */
2913 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2914 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2916 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2917 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2918 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2920 if (!isInit && !isFinal)
2921 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2922 else if (isInit)
2923 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2924 else
2925 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2927 else if (!isInit)
2929 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2930 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2931 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2932 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2933 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2934 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2935 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2936 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2937 else
2938 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2940 else if (!isInit && !isFinal)
2941 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2942 else
2943 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2945 else if (char_count == 2)
2947 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2948 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2949 else if (!isInit)
2950 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2951 else
2952 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2954 else if (!isInit && !isFinal)
2955 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2956 else
2957 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2960 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2961 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2962 HeapFree(GetProcessHeap(),0,spaces);
2965 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 )
2967 int i,k;
2968 int finaGlyph;
2969 INT dirL;
2970 BYTE *spaces;
2972 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2973 memset(spaces,0,cGlyphs);
2975 if (!psa->fLogicalOrder && psa->fRTL)
2977 finaGlyph = 0;
2978 dirL = -1;
2980 else
2982 finaGlyph = cGlyphs-1;
2983 dirL = 1;
2986 for (i = 0; i < cGlyphs; i++)
2988 for (k = 0; k < cChars; k++)
2989 if (pwLogClust[k] == i)
2991 if (pwcChars[k] == 0x0020)
2992 spaces[i] = 1;
2996 for (i = 0; i < cGlyphs; i++)
2998 int char_index[20];
2999 int char_count = 0;
3001 for (k = 0; k < cChars; k++)
3003 if (pwLogClust[k] == i)
3005 char_index[char_count] = k;
3006 char_count++;
3010 if (char_count == 0)
3012 FIXME("No chars in this glyph? Must be an error\n");
3013 continue;
3016 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3018 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3019 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3021 else if (i == finaGlyph)
3022 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3023 else
3024 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3027 HeapFree(GetProcessHeap(),0,spaces);
3028 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3029 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3031 /* Do not allow justification between marks and their base */
3032 for (i = 0; i < cGlyphs; i++)
3034 if (!pGlyphProp[i].sva.fClusterStart)
3035 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3039 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)
3041 int i,k;
3043 for (i = 0; i < cGlyphs; i++)
3045 int char_index[20];
3046 int char_count = 0;
3048 for (k = 0; k < cChars; k++)
3050 if (pwLogClust[k] == i)
3052 char_index[char_count] = k;
3053 char_count++;
3057 if (char_count == 0)
3059 FIXME("No chars in this glyph? Must be an error\n");
3060 continue;
3063 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3065 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3066 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3068 else
3069 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3071 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3072 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3075 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)
3077 int i,k;
3079 for (i = 0; i < cGlyphs; i++)
3081 int char_index[20];
3082 int char_count = 0;
3084 for (k = 0; k < cChars; k++)
3086 if (pwLogClust[k] == i)
3088 char_index[char_count] = k;
3089 char_count++;
3093 if (char_count == 0)
3095 FIXME("No chars in this glyph? Must be an error\n");
3096 continue;
3099 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3101 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3102 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3104 else
3105 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3107 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3108 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3110 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3111 for (i = 0; i < cGlyphs; i++)
3113 if (!pGlyphProp[i].sva.fClusterStart)
3115 pGlyphProp[i].sva.fDiacritic = 0;
3116 pGlyphProp[i].sva.fZeroWidth = 0;
3121 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)
3123 int i,k;
3125 for (i = 0; i < cGlyphs; i++)
3127 int char_index[20];
3128 int char_count = 0;
3130 for (k = 0; k < cChars; k++)
3132 if (pwLogClust[k] == i)
3134 char_index[char_count] = k;
3135 char_count++;
3139 if (char_count == 0)
3141 FIXME("No chars in this glyph? Must be an error\n");
3142 continue;
3145 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3147 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3148 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3150 else
3151 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3153 pGlyphProp[i].sva.fClusterStart = 0;
3154 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3155 switch (lexical(pwcChars[char_index[k]]))
3157 case lex_Matra_pre:
3158 case lex_Matra_post:
3159 case lex_Matra_above:
3160 case lex_Matra_below:
3161 case lex_Modifier:
3162 break;
3163 default:
3164 pGlyphProp[i].sva.fClusterStart = 1;
3165 break;
3168 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3171 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 )
3173 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3176 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 )
3178 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3181 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 )
3183 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3186 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 )
3188 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3191 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 )
3193 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3196 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 )
3198 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3201 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 )
3203 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3206 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 )
3208 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3211 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 )
3213 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3216 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)
3218 if (ShapingData[psa->eScript].charGlyphPropProc)
3219 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3220 else
3221 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3224 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3226 if (ShapingData[psa->eScript].contextProc)
3227 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3230 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)
3232 int i;
3233 INT dirL;
3235 if (!rpRangeProperties)
3236 return;
3238 if (!psc->GSUB_Table)
3239 psc->GSUB_Table = load_gsub_table(hdc);
3241 if (!psc->GSUB_Table)
3242 return;
3244 if (!psa->fLogicalOrder && psa->fRTL)
3245 dirL = -1;
3246 else
3247 dirL = 1;
3249 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3251 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3252 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3256 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3258 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3259 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3261 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3264 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3266 const GSUB_Feature *feature;
3267 int i;
3269 if (!ShapingData[psa->eScript].requiredFeatures)
3270 return S_OK;
3272 if (!psc->GSUB_Table)
3273 psc->GSUB_Table = load_gsub_table(hdc);
3275 /* we need to have at least one of the required features */
3276 i = 0;
3277 while (ShapingData[psa->eScript].requiredFeatures[i])
3279 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3280 if (feature)
3281 return S_OK;
3282 i++;
3285 return USP_E_SCRIPT_NOT_IN_FONT;