po: Update Catalan translation.
[wine.git] / dlls / usp10 / shape.c
blobd0ab0b2bfd99b5bcaa685bb7027abff4561252c9
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "usp10.h"
29 #include "winternl.h"
31 #include "usp10_internal.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
37 #define FIRST_ARABIC_CHAR 0x0600
38 #define LAST_ARABIC_CHAR 0x06ff
40 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
41 WCHAR*, INT, WORD*, INT*, INT, WORD*);
43 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
61 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);
62 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 );
63 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 );
64 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 );
65 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 );
66 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
67 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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
78 extern const unsigned short indic_syllabic_table[];
79 extern const unsigned short wine_shaping_table[];
80 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
82 enum joining_types {
83 jtU,
84 jtT,
85 jtR,
86 jtL,
87 jtD,
88 jtC
91 enum joined_forms {
92 Xn=0,
93 Xr,
94 Xl,
95 Xm,
96 /* Syriac Alaph */
97 Afj,
98 Afn,
99 Afx
102 #ifdef WORDS_BIGENDIAN
103 #define GET_BE_WORD(x) (x)
104 #else
105 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
106 #endif
108 /* These are all structures needed for the GSUB table */
109 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
110 #define GSUB_E_NOFEATURE -2
111 #define GSUB_E_NOGLYPH -1
113 typedef struct {
114 DWORD version;
115 WORD ScriptList;
116 WORD FeatureList;
117 WORD LookupList;
118 } GSUB_Header;
120 typedef struct {
121 CHAR ScriptTag[4];
122 WORD Script;
123 } GSUB_ScriptRecord;
125 typedef struct {
126 WORD ScriptCount;
127 GSUB_ScriptRecord ScriptRecord[1];
128 } GSUB_ScriptList;
130 typedef struct {
131 CHAR LangSysTag[4];
132 WORD LangSys;
133 } GSUB_LangSysRecord;
135 typedef struct {
136 WORD DefaultLangSys;
137 WORD LangSysCount;
138 GSUB_LangSysRecord LangSysRecord[1];
139 } GSUB_Script;
141 typedef struct {
142 WORD LookupOrder; /* Reserved */
143 WORD ReqFeatureIndex;
144 WORD FeatureCount;
145 WORD FeatureIndex[1];
146 } GSUB_LangSys;
148 typedef struct {
149 CHAR FeatureTag[4];
150 WORD Feature;
151 } GSUB_FeatureRecord;
153 typedef struct {
154 WORD FeatureCount;
155 GSUB_FeatureRecord FeatureRecord[1];
156 } GSUB_FeatureList;
158 typedef struct {
159 WORD FeatureParams; /* Reserved */
160 WORD LookupCount;
161 WORD LookupListIndex[1];
162 } GSUB_Feature;
164 typedef struct {
165 WORD LookupCount;
166 WORD Lookup[1];
167 } GSUB_LookupList;
169 typedef struct {
170 WORD LookupType;
171 WORD LookupFlag;
172 WORD SubTableCount;
173 WORD SubTable[1];
174 } GSUB_LookupTable;
176 typedef struct {
177 WORD CoverageFormat;
178 WORD GlyphCount;
179 WORD GlyphArray[1];
180 } GSUB_CoverageFormat1;
182 typedef struct {
183 WORD Start;
184 WORD End;
185 WORD StartCoverageIndex;
186 } GSUB_RangeRecord;
188 typedef struct {
189 WORD CoverageFormat;
190 WORD RangeCount;
191 GSUB_RangeRecord RangeRecord[1];
192 } GSUB_CoverageFormat2;
194 typedef struct {
195 WORD SubstFormat; /* = 1 */
196 WORD Coverage;
197 WORD DeltaGlyphID;
198 } GSUB_SingleSubstFormat1;
200 typedef struct {
201 WORD SubstFormat; /* = 2 */
202 WORD Coverage;
203 WORD GlyphCount;
204 WORD Substitute[1];
205 }GSUB_SingleSubstFormat2;
207 typedef struct {
208 WORD SubstFormat; /* = 1 */
209 WORD Coverage;
210 WORD SequenceCount;
211 WORD Sequence[1];
212 }GSUB_MultipleSubstFormat1;
214 typedef struct {
215 WORD GlyphCount;
216 WORD Substitute[1];
217 }GSUB_Sequence;
219 typedef struct {
220 WORD SubstFormat; /* = 1 */
221 WORD Coverage;
222 WORD LigSetCount;
223 WORD LigatureSet[1];
224 }GSUB_LigatureSubstFormat1;
226 typedef struct {
227 WORD LigatureCount;
228 WORD Ligature[1];
229 }GSUB_LigatureSet;
231 typedef struct{
232 WORD LigGlyph;
233 WORD CompCount;
234 WORD Component[1];
235 }GSUB_Ligature;
237 typedef struct{
238 WORD SequenceIndex;
239 WORD LookupListIndex;
241 }GSUB_SubstLookupRecord;
243 typedef struct{
244 WORD SubstFormat; /* = 1 */
245 WORD Coverage;
246 WORD ChainSubRuleSetCount;
247 WORD ChainSubRuleSet[1];
248 }GSUB_ChainContextSubstFormat1;
250 typedef struct {
251 WORD SubstFormat; /* = 3 */
252 WORD BacktrackGlyphCount;
253 WORD Coverage[1];
254 }GSUB_ChainContextSubstFormat3_1;
256 typedef struct{
257 WORD InputGlyphCount;
258 WORD Coverage[1];
259 }GSUB_ChainContextSubstFormat3_2;
261 typedef struct{
262 WORD LookaheadGlyphCount;
263 WORD Coverage[1];
264 }GSUB_ChainContextSubstFormat3_3;
266 typedef struct{
267 WORD SubstCount;
268 GSUB_SubstLookupRecord SubstLookupRecord[1];
269 }GSUB_ChainContextSubstFormat3_4;
271 typedef struct {
272 WORD SubstFormat; /* = 1 */
273 WORD Coverage;
274 WORD AlternateSetCount;
275 WORD AlternateSet[1];
276 } GSUB_AlternateSubstFormat1;
278 typedef struct{
279 WORD GlyphCount;
280 WORD Alternate[1];
281 } GSUB_AlternateSet;
283 /* These are all structures needed for the GDEF table */
284 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
286 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
288 typedef struct {
289 DWORD Version;
290 WORD GlyphClassDef;
291 WORD AttachList;
292 WORD LigCaretList;
293 WORD MarkAttachClassDef;
294 } GDEF_Header;
296 typedef struct {
297 WORD ClassFormat;
298 WORD StartGlyph;
299 WORD GlyphCount;
300 WORD ClassValueArray[1];
301 } GDEF_ClassDefFormat1;
303 typedef struct {
304 WORD Start;
305 WORD End;
306 WORD Class;
307 } GDEF_ClassRangeRecord;
309 typedef struct {
310 WORD ClassFormat;
311 WORD ClassRangeCount;
312 GDEF_ClassRangeRecord ClassRangeRecord[1];
313 } GDEF_ClassDefFormat2;
315 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
317 typedef struct tagVowelComponents
319 WCHAR base;
320 WCHAR parts[3];
321 } VowelComponents;
323 typedef struct tagConsonantComponents
325 WCHAR parts[3];
326 WCHAR output;
327 } ConsonantComponents;
329 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
331 /* the orders of joined_forms and contextual_features need to line up */
332 static const char* contextual_features[] =
334 "isol",
335 "fina",
336 "init",
337 "medi",
338 /* Syriac Alaph */
339 "med2",
340 "fin2",
341 "fin3"
344 static OPENTYPE_FEATURE_RECORD standard_features[] =
346 { MS_MAKE_TAG('c','c','m','p'), 1},
347 { MS_MAKE_TAG('l','o','c','l'), 1},
350 static OPENTYPE_FEATURE_RECORD latin_features[] =
352 { MS_MAKE_TAG('l','i','g','a'), 1},
353 { MS_MAKE_TAG('c','l','i','g'), 1},
356 static OPENTYPE_FEATURE_RECORD arabic_features[] =
358 { MS_MAKE_TAG('r','l','i','g'), 1},
359 { MS_MAKE_TAG('c','a','l','t'), 1},
360 { MS_MAKE_TAG('l','i','g','a'), 1},
361 { MS_MAKE_TAG('d','l','i','g'), 1},
362 { MS_MAKE_TAG('c','s','w','h'), 1},
363 { MS_MAKE_TAG('m','s','e','t'), 1},
366 static const char* required_arabic_features[] =
368 "fina",
369 "init",
370 "medi",
371 "rlig",
372 NULL
375 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
377 { MS_MAKE_TAG('d','l','i','g'), 0},
380 static OPENTYPE_FEATURE_RECORD syriac_features[] =
382 { MS_MAKE_TAG('r','l','i','g'), 1},
383 { MS_MAKE_TAG('c','a','l','t'), 1},
384 { MS_MAKE_TAG('l','i','g','a'), 1},
385 { MS_MAKE_TAG('d','l','i','g'), 1},
388 static const char* required_syriac_features[] =
390 "fina",
391 "fin2",
392 "fin3",
393 "init",
394 "medi",
395 "med2",
396 "rlig",
397 NULL
400 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
402 /* Presentation forms */
403 { MS_MAKE_TAG('b','l','w','s'), 1},
404 { MS_MAKE_TAG('a','b','v','s'), 1},
405 { MS_MAKE_TAG('p','s','t','s'), 1},
408 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
410 { MS_MAKE_TAG('a','b','v','s'), 1},
411 { MS_MAKE_TAG('b','l','w','s'), 1},
414 static OPENTYPE_FEATURE_RECORD phags_features[] =
416 { MS_MAKE_TAG('a','b','v','s'), 1},
417 { MS_MAKE_TAG('b','l','w','s'), 1},
418 { MS_MAKE_TAG('c','a','l','t'), 1},
421 static OPENTYPE_FEATURE_RECORD thai_features[] =
423 { MS_MAKE_TAG('c','c','m','p'), 1},
426 static const char* required_lao_features[] =
428 "ccmp",
429 NULL
432 static const char* required_devanagari_features[] =
434 "nukt",
435 "akhn",
436 "rphf",
437 "blwf",
438 "half",
439 "vatu",
440 "pres",
441 "abvs",
442 "blws",
443 "psts",
444 "haln",
445 NULL
448 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
450 { MS_MAKE_TAG('p','r','e','s'), 1},
451 { MS_MAKE_TAG('a','b','v','s'), 1},
452 { MS_MAKE_TAG('b','l','w','s'), 1},
453 { MS_MAKE_TAG('p','s','t','s'), 1},
454 { MS_MAKE_TAG('h','a','l','n'), 1},
455 { MS_MAKE_TAG('c','a','l','t'), 1},
458 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
460 { MS_MAKE_TAG('l','i','g','a'), 1},
461 { MS_MAKE_TAG('c','l','i','g'), 1},
464 static const char* required_bengali_features[] =
466 "nukt",
467 "akhn",
468 "rphf",
469 "blwf",
470 "half",
471 "vatu",
472 "pstf",
473 "init",
474 "abvs",
475 "blws",
476 "psts",
477 "haln",
478 NULL
481 static const char* required_gurmukhi_features[] =
483 "nukt",
484 "akhn",
485 "rphf",
486 "blwf",
487 "half",
488 "pstf",
489 "vatu",
490 "cjct",
491 "pres",
492 "abvs",
493 "blws",
494 "psts",
495 "haln",
496 "calt",
497 NULL
500 static const char* required_oriya_features[] =
502 "nukt",
503 "akhn",
504 "rphf",
505 "blwf",
506 "pstf",
507 "cjct",
508 "pres",
509 "abvs",
510 "blws",
511 "psts",
512 "haln",
513 "calt",
514 NULL
517 static const char* required_tamil_features[] =
519 "nukt",
520 "akhn",
521 "rphf",
522 "pref",
523 "half",
524 "pres",
525 "abvs",
526 "blws",
527 "psts",
528 "haln",
529 "calt",
530 NULL
533 static const char* required_telugu_features[] =
535 "nukt",
536 "akhn",
537 "rphf",
538 "pref",
539 "half",
540 "pstf",
541 "cjct",
542 "pres",
543 "abvs",
544 "blws",
545 "psts",
546 "haln",
547 "calt",
548 NULL
551 static OPENTYPE_FEATURE_RECORD khmer_features[] =
553 { MS_MAKE_TAG('p','r','e','s'), 1},
554 { MS_MAKE_TAG('b','l','w','s'), 1},
555 { MS_MAKE_TAG('a','b','v','s'), 1},
556 { MS_MAKE_TAG('p','s','t','s'), 1},
557 { MS_MAKE_TAG('c','l','i','g'), 1},
560 static const char* required_khmer_features[] =
562 "pref",
563 "blwf",
564 "abvf",
565 "pstf",
566 "pres",
567 "blws",
568 "abvs",
569 "psts",
570 "clig",
571 NULL
574 static OPENTYPE_FEATURE_RECORD no_features[] =
575 { };
577 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
579 { MS_MAKE_TAG('c','c','m','p'), 1},
580 { MS_MAKE_TAG('l','o','c','l'), 1},
581 { MS_MAKE_TAG('c','a','l','t'), 1},
582 { MS_MAKE_TAG('l','i','g','a'), 1},
585 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
587 { MS_MAKE_TAG('c','c','m','p'), 1},
588 { MS_MAKE_TAG('l','o','c','l'), 1},
589 { MS_MAKE_TAG('c','a','l','t'), 1},
590 { MS_MAKE_TAG('r','l','i','g'), 1},
593 typedef struct ScriptShapeDataTag {
594 TEXTRANGE_PROPERTIES defaultTextRange;
595 const char** requiredFeatures;
596 CHAR otTag[5];
597 CHAR newOtTag[5];
598 ContextualShapingProc contextProc;
599 ShapeCharGlyphPropProc charGlyphPropProc;
600 } ScriptShapeData;
602 /* in order of scripts */
603 static const ScriptShapeData ShapingData[] =
605 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
606 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
607 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
608 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
609 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
610 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
611 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
612 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
613 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
614 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
615 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
616 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
617 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
618 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
619 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
620 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
621 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
622 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
623 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
624 {{ phags_features, 3}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
625 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
626 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
627 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
628 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
629 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
630 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
631 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
632 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
633 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
634 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
635 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
636 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
637 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
638 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
639 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
640 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
641 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
642 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
643 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
644 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
645 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
646 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
647 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
648 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
649 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
650 {{ latin_features, 2}, NULL, "latn" , "", NULL, NULL},
651 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
652 {{ myanmar_features, 2}, NULL, "mymr", "", NULL, NULL},
653 {{ myanmar_features, 2}, NULL, "mymr", "", NULL, NULL},
654 {{ standard_features, 2}, NULL, "tale", "", NULL, NULL},
655 {{ standard_features, 2}, NULL, "talu", "", NULL, NULL},
656 {{ standard_features, 2}, NULL, "talu", "", NULL, NULL},
657 {{ khmer_features, 5}, required_khmer_features, "khmr", "", ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
658 {{ khmer_features, 5}, required_khmer_features, "khmr", "", ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
659 {{ no_features, 0}, NULL, "hani", "", NULL, NULL},
660 {{ no_features, 0}, NULL, "hani", "", NULL, NULL},
661 {{ no_features, 0}, NULL, "bopo", "", NULL, NULL},
662 {{ no_features, 0}, NULL, "kana", "", NULL, NULL},
663 {{ no_features, 0}, NULL, "hang", "", NULL, NULL},
664 {{ no_features, 0}, NULL, "yi ", "", NULL, NULL},
665 {{ ethiopic_features, 4}, NULL, "ethi", "", NULL, NULL},
666 {{ ethiopic_features, 4}, NULL, "ethi", "", NULL, NULL},
667 {{ mongolian_features, 4}, NULL, "mong", "", ContextualShape_Mongolian, NULL},
668 {{ mongolian_features, 4}, NULL, "mong", "", ContextualShape_Mongolian, NULL},
669 {{ no_features, 0}, NULL, "tfng", "", NULL, NULL},
670 {{ no_features, 0}, NULL, "nko ", "", NULL, NULL},
671 {{ no_features, 0}, NULL, "vai ", "", NULL, NULL},
672 {{ no_features, 0}, NULL, "vai ", "", NULL, NULL},
673 {{ no_features, 0}, NULL, "cher", "", NULL, NULL},
674 {{ no_features, 0}, NULL, "cans", "", NULL, NULL},
675 {{ no_features, 0}, NULL, "ogam", "", NULL, NULL},
676 {{ no_features, 0}, NULL, "runr", "", NULL, NULL},
677 {{ no_features, 0}, NULL, "brai", "", NULL, NULL},
678 {{ no_features, 0}, NULL, "", "", NULL, NULL},
679 {{ no_features, 0}, NULL, "", "", NULL, NULL},
682 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
684 const GSUB_CoverageFormat1* cf1;
686 cf1 = table;
688 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
690 int count = GET_BE_WORD(cf1->GlyphCount);
691 int i;
692 TRACE("Coverage Format 1, %i glyphs\n",count);
693 for (i = 0; i < count; i++)
694 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
695 return i;
696 return -1;
698 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
700 const GSUB_CoverageFormat2* cf2;
701 int i;
702 int count;
703 cf2 = (const GSUB_CoverageFormat2*)cf1;
705 count = GET_BE_WORD(cf2->RangeCount);
706 TRACE("Coverage Format 2, %i ranges\n",count);
707 for (i = 0; i < count; i++)
709 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
710 return -1;
711 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
712 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
714 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
715 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
718 return -1;
720 else
721 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
723 return -1;
726 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
728 const GSUB_ScriptList *script;
729 const GSUB_Script *deflt = NULL;
730 int i;
731 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
733 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
734 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
736 const GSUB_Script *scr;
737 int offset;
739 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
740 scr = (const GSUB_Script*)((const BYTE*)script + offset);
742 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
743 return scr;
744 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
745 deflt = scr;
747 return deflt;
750 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
752 int i;
753 int offset;
754 const GSUB_LangSys *Lang;
756 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
758 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
760 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
761 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
763 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
764 return Lang;
766 offset = GET_BE_WORD(script->DefaultLangSys);
767 if (offset)
769 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
770 return Lang;
772 return NULL;
775 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
777 int i;
778 const GSUB_FeatureList *feature;
779 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
781 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
782 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
784 int index = GET_BE_WORD(lang->FeatureIndex[i]);
785 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
787 const GSUB_Feature *feat;
788 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
789 return feat;
792 return NULL;
795 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
797 int j;
798 TRACE("Single Substitution Subtable\n");
800 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
802 int offset;
803 const GSUB_SingleSubstFormat1 *ssf1;
804 offset = GET_BE_WORD(look->SubTable[j]);
805 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
806 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
808 int offset = GET_BE_WORD(ssf1->Coverage);
809 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
810 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
812 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
813 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
814 TRACE(" 0x%x\n",glyphs[glyph_index]);
815 return glyph_index + write_dir;
818 else
820 const GSUB_SingleSubstFormat2 *ssf2;
821 INT index;
822 INT offset;
824 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
825 offset = GET_BE_WORD(ssf1->Coverage);
826 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
827 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
828 TRACE(" Coverage index %i\n",index);
829 if (index != -1)
831 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
832 return GSUB_E_NOGLYPH;
834 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
835 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
836 TRACE("0x%x\n",glyphs[glyph_index]);
837 return glyph_index + write_dir;
841 return GSUB_E_NOGLYPH;
844 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
846 int j;
847 TRACE("Multiple Substitution Subtable\n");
849 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
851 int offset, index;
852 const GSUB_MultipleSubstFormat1 *msf1;
853 offset = GET_BE_WORD(look->SubTable[j]);
854 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
856 offset = GET_BE_WORD(msf1->Coverage);
857 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
858 if (index != -1)
860 const GSUB_Sequence *seq;
861 int sub_count;
862 int j;
863 offset = GET_BE_WORD(msf1->Sequence[index]);
864 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
865 sub_count = GET_BE_WORD(seq->GlyphCount);
866 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
868 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
869 glyphs[j] =glyphs[j-(sub_count-1)];
871 for (j = 0; j < sub_count; j++)
872 if (write_dir < 0)
873 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
874 else
875 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
877 *glyph_count = *glyph_count + (sub_count - 1);
879 if (TRACE_ON(uniscribe))
881 for (j = 0; j < sub_count; j++)
882 TRACE(" 0x%x",glyphs[glyph_index+j]);
883 TRACE("\n");
886 return glyph_index + (sub_count * write_dir);
889 return GSUB_E_NOGLYPH;
892 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
894 int j;
895 TRACE("Alternate Substitution Subtable\n");
897 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
899 int offset;
900 const GSUB_AlternateSubstFormat1 *asf1;
901 INT index;
903 offset = GET_BE_WORD(look->SubTable[j]);
904 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
905 offset = GET_BE_WORD(asf1->Coverage);
907 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
908 if (index != -1)
910 const GSUB_AlternateSet *as;
911 offset = GET_BE_WORD(asf1->AlternateSet[index]);
912 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
913 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
914 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
915 return GSUB_E_NOGLYPH;
917 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
918 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
919 TRACE(" 0x%x\n",glyphs[glyph_index]);
920 return glyph_index + write_dir;
923 return GSUB_E_NOGLYPH;
926 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
928 int j;
930 TRACE("Ligature Substitution Subtable\n");
931 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
933 const GSUB_LigatureSubstFormat1 *lsf1;
934 int offset,index;
936 offset = GET_BE_WORD(look->SubTable[j]);
937 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
938 offset = GET_BE_WORD(lsf1->Coverage);
939 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
940 TRACE(" Coverage index %i\n",index);
941 if (index != -1)
943 const GSUB_LigatureSet *ls;
944 int k, count;
946 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
947 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
948 count = GET_BE_WORD(ls->LigatureCount);
949 TRACE(" LigatureSet has %i members\n",count);
950 for (k = 0; k < count; k++)
952 const GSUB_Ligature *lig;
953 int CompCount,l,CompIndex;
955 offset = GET_BE_WORD(ls->Ligature[k]);
956 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
957 CompCount = GET_BE_WORD(lig->CompCount) - 1;
958 CompIndex = glyph_index+write_dir;
959 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
961 int CompGlyph;
962 CompGlyph = GET_BE_WORD(lig->Component[l]);
963 if (CompGlyph != glyphs[CompIndex])
964 break;
965 CompIndex += write_dir;
967 if (l == CompCount)
969 int replaceIdx = glyph_index;
970 if (write_dir < 0)
971 replaceIdx = glyph_index - CompCount;
973 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
974 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
975 TRACE("0x%x\n",glyphs[replaceIdx]);
976 if (CompCount > 0)
978 int j;
979 for (j = replaceIdx + 1; j < *glyph_count; j++)
980 glyphs[j] =glyphs[j+CompCount];
981 *glyph_count = *glyph_count - CompCount;
983 return replaceIdx + write_dir;
988 return GSUB_E_NOGLYPH;
991 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
993 int j;
994 BOOL done = FALSE;
996 TRACE("Chaining Contextual Substitution Subtable\n");
997 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
999 const GSUB_ChainContextSubstFormat1 *ccsf1;
1000 int offset;
1001 int dirLookahead = write_dir;
1002 int dirBacktrack = -1 * write_dir;
1004 offset = GET_BE_WORD(look->SubTable[j]);
1005 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
1006 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
1008 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
1009 continue;
1011 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
1013 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
1014 continue;
1016 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
1018 int k;
1019 int indexGlyphs;
1020 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
1021 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
1022 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
1023 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
1024 int newIndex = glyph_index;
1026 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
1028 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
1030 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
1032 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
1033 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
1034 break;
1036 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
1037 continue;
1038 TRACE("Matched Backtrack\n");
1040 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
1042 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
1043 for (k = 0; k < indexGlyphs; k++)
1045 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
1046 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
1047 break;
1049 if (k != indexGlyphs)
1050 continue;
1051 TRACE("Matched IndexGlyphs\n");
1053 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
1055 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
1057 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
1058 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
1059 break;
1061 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
1062 continue;
1063 TRACE("Matched LookAhead\n");
1065 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
1067 if (GET_BE_WORD(ccsf3_4->SubstCount))
1069 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
1071 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
1072 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
1074 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1075 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
1076 if (newIndex == -1)
1078 ERR("Chain failed to generate a glyph\n");
1079 continue;
1082 return newIndex;
1084 else return GSUB_E_NOGLYPH;
1087 return -1;
1090 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1092 int offset;
1093 const GSUB_LookupTable *look;
1095 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1096 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1097 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1098 switch(GET_BE_WORD(look->LookupType))
1100 case 1:
1101 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1102 case 2:
1103 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1104 case 3:
1105 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1106 case 4:
1107 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1108 case 6:
1109 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1110 default:
1111 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1113 return GSUB_E_NOGLYPH;
1116 static INT GSUB_apply_feature_all_lookups(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1118 int i;
1119 int out_index = GSUB_E_NOGLYPH;
1120 const GSUB_LookupList *lookup;
1122 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1124 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1125 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1127 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1128 if (out_index != GSUB_E_NOGLYPH)
1129 break;
1131 if (out_index == GSUB_E_NOGLYPH)
1132 TRACE("lookups found no glyphs\n");
1133 else
1135 int out2;
1136 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1137 if (out2!=GSUB_E_NOGLYPH)
1138 out_index = out2;
1140 return out_index;
1143 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1145 UINT charset;
1147 if (psc->userScript != 0)
1149 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1150 return ShapingData[psa->eScript].newOtTag;
1151 else
1152 return (char*)&psc->userScript;
1155 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1156 return ShapingData[psa->eScript].newOtTag;
1158 if (ShapingData[psa->eScript].otTag[0] != 0)
1159 return ShapingData[psa->eScript].otTag;
1162 * fall back to the font charset
1164 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1165 switch (charset)
1167 case ANSI_CHARSET: return "latn";
1168 case BALTIC_CHARSET: return "latn"; /* ?? */
1169 case CHINESEBIG5_CHARSET: return "hani";
1170 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1171 case GB2312_CHARSET: return "hani";
1172 case GREEK_CHARSET: return "grek";
1173 case HANGUL_CHARSET: return "hang";
1174 case RUSSIAN_CHARSET: return "cyrl";
1175 case SHIFTJIS_CHARSET: return "kana";
1176 case TURKISH_CHARSET: return "latn"; /* ?? */
1177 case VIETNAMESE_CHARSET: return "latn";
1178 case JOHAB_CHARSET: return "latn"; /* ?? */
1179 case ARABIC_CHARSET: return "arab";
1180 case HEBREW_CHARSET: return "hebr";
1181 case THAI_CHARSET: return "thai";
1182 default: return "latn";
1186 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1188 const GSUB_Feature *feature;
1189 const char* script;
1190 int i;
1192 script = get_opentype_script(hdc,psa,psc,FALSE);
1194 for (i = 0; i < psc->feature_count; i++)
1196 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1197 return psc->features[i].feature;
1200 feature = NULL;
1202 if (psc->GSUB_Table)
1204 const GSUB_Script *script;
1205 const GSUB_LangSys *language;
1206 int attempt = 2;
1210 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1211 attempt--;
1212 if (script)
1214 if (psc->userLang != 0)
1215 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1216 else
1217 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1218 if (language)
1219 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1221 } while(attempt && !feature);
1223 /* try in the default (latin) table */
1224 if (!feature)
1226 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1227 if (script)
1229 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1230 if (language)
1231 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1236 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1238 psc->feature_count++;
1240 if (psc->features)
1241 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1242 else
1243 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1245 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1246 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1247 psc->features[psc->feature_count - 1].feature = feature;
1248 return feature;
1251 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)
1253 const GSUB_Feature *feature;
1255 feature = load_GSUB_feature(hdc, psa, psc, feat);
1256 if (!feature)
1257 return GSUB_E_NOFEATURE;
1259 TRACE("applying feature %s\n",feat);
1260 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1263 static VOID *load_gsub_table(HDC hdc)
1265 VOID* GSUB_Table = NULL;
1266 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1267 if (length != GDI_ERROR)
1269 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1270 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1271 TRACE("Loaded GSUB table of %i bytes\n",length);
1273 return GSUB_Table;
1276 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)
1278 WORD *glyphs;
1279 INT glyph_count = count;
1280 INT rc;
1282 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1283 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1284 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1285 if (rc > GSUB_E_NOGLYPH)
1286 rc = count - glyph_count;
1287 else
1288 rc = 0;
1290 HeapFree(GetProcessHeap(),0,glyphs);
1291 return rc;
1294 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1296 int offset;
1297 WORD class = 0;
1298 const GDEF_ClassDefFormat1 *cf1;
1300 if (!header)
1301 return 0;
1303 offset = GET_BE_WORD(header->GlyphClassDef);
1304 if (!offset)
1305 return 0;
1307 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1308 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1310 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1312 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1313 if (index < GET_BE_WORD(cf1->GlyphCount))
1314 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1317 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1319 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1320 int i, top;
1321 top = GET_BE_WORD(cf2->ClassRangeCount);
1322 for (i = 0; i < top; i++)
1324 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1325 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1327 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1328 break;
1332 else
1333 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1335 return class;
1338 static VOID *load_gdef_table(HDC hdc)
1340 VOID* GDEF_Table = NULL;
1341 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1342 if (length != GDI_ERROR)
1344 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1345 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1346 TRACE("Loaded GDEF table of %i bytes\n",length);
1348 return GDEF_Table;
1351 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
1353 int i;
1355 if (!psc->GDEF_Table)
1356 psc->GDEF_Table = load_gdef_table(hdc);
1358 for (i = 0; i < cGlyphs; i++)
1360 WORD class;
1361 int char_count = 0;
1362 int k;
1364 for (k = 0; k < cChars; k++)
1365 if (pwLogClust[k] == i)
1366 char_count++;
1368 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1370 switch (class)
1372 case 0:
1373 case BaseGlyph:
1374 pGlyphProp[i].sva.fClusterStart = 1;
1375 pGlyphProp[i].sva.fDiacritic = 0;
1376 pGlyphProp[i].sva.fZeroWidth = 0;
1377 break;
1378 case LigatureGlyph:
1379 pGlyphProp[i].sva.fClusterStart = 1;
1380 pGlyphProp[i].sva.fDiacritic = 0;
1381 pGlyphProp[i].sva.fZeroWidth = 0;
1382 break;
1383 case MarkGlyph:
1384 pGlyphProp[i].sva.fClusterStart = 0;
1385 pGlyphProp[i].sva.fDiacritic = 1;
1386 pGlyphProp[i].sva.fZeroWidth = 1;
1387 break;
1388 case ComponentGlyph:
1389 pGlyphProp[i].sva.fClusterStart = 0;
1390 pGlyphProp[i].sva.fDiacritic = 0;
1391 pGlyphProp[i].sva.fZeroWidth = 0;
1392 break;
1393 default:
1394 ERR("Unknown glyph class %i\n",class);
1395 pGlyphProp[i].sva.fClusterStart = 1;
1396 pGlyphProp[i].sva.fDiacritic = 0;
1397 pGlyphProp[i].sva.fZeroWidth = 0;
1400 if (char_count == 0)
1401 pGlyphProp[i].sva.fClusterStart = 0;
1405 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1407 int i;
1409 for (i = 0; i < cGlyphs; i++)
1411 if (!pGlyphProp[i].sva.fClusterStart)
1413 int j;
1414 for (j = 0; j < cChars; j++)
1416 if (pwLogClust[j] == i)
1418 int k = j;
1419 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1420 k-=1;
1421 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1422 pwLogClust[j] = pwLogClust[k];
1429 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1431 if (changeCount == 0)
1432 return;
1433 else
1435 int i;
1436 int target_glyph = nextIndex - write_dir;
1437 int seeking_glyph;
1438 int target_index = -1;
1439 int replacing_glyph = -1;
1440 int changed = 0;
1441 int top_logclust = 0;
1443 if (changeCount > 0)
1445 if (write_dir > 0)
1446 target_glyph = nextIndex - changeCount;
1447 else
1448 target_glyph = nextIndex + (changeCount + 1);
1451 seeking_glyph = target_glyph;
1452 for (i = 0; i < chars; i++)
1453 if (pwLogClust[i] > top_logclust)
1454 top_logclust = pwLogClust[i];
1456 do {
1457 if (write_dir > 0)
1458 for (i = 0; i < chars; i++)
1460 if (pwLogClust[i] == seeking_glyph)
1462 target_index = i;
1463 break;
1466 else
1467 for (i = chars - 1; i >= 0; i--)
1469 if (pwLogClust[i] == seeking_glyph)
1471 target_index = i;
1472 break;
1475 if (target_index == -1)
1476 seeking_glyph ++;
1478 while (target_index == -1 && seeking_glyph <= top_logclust);
1480 if (target_index == -1)
1482 ERR("Unable to find target glyph\n");
1483 return;
1486 if (changeCount < 0)
1488 /* merge glyphs */
1489 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1491 if (pwLogClust[i] == target_glyph)
1492 continue;
1493 if(pwLogClust[i] == replacing_glyph)
1494 pwLogClust[i] = target_glyph;
1495 else
1497 changed--;
1498 if (changed >= changeCount)
1500 replacing_glyph = pwLogClust[i];
1501 pwLogClust[i] = target_glyph;
1503 else
1504 break;
1508 /* renumber trailing indexes*/
1509 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1511 if (pwLogClust[i] != target_glyph)
1512 pwLogClust[i] += changeCount;
1515 else
1517 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1518 pwLogClust[i] += changeCount;
1523 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 )
1525 if (psc->GSUB_Table)
1527 const GSUB_Feature *feature;
1528 const GSUB_LookupList *lookup;
1529 const GSUB_Header *header = psc->GSUB_Table;
1530 int lookup_index, lookup_count;
1532 feature = load_GSUB_feature(hdc, psa, psc, feat);
1533 if (!feature)
1534 return GSUB_E_NOFEATURE;
1536 TRACE("applying feature %s\n",debugstr_an(feat,4));
1537 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1538 lookup_count = GET_BE_WORD(feature->LookupCount);
1539 TRACE("%i lookups\n", lookup_count);
1540 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1542 int i;
1544 if (write_dir > 0)
1545 i = 0;
1546 else
1547 i = *pcGlyphs-1;
1548 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1549 while(i < *pcGlyphs && i >= 0)
1551 INT nextIndex;
1552 INT prevCount = *pcGlyphs;
1554 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1555 if (*pcGlyphs != prevCount)
1557 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1558 i = nextIndex;
1560 else
1561 i+=write_dir;
1564 return *pcGlyphs;
1566 return GSUB_E_NOFEATURE;
1569 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1571 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1574 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1576 if (i + delta < 0)
1577 return 0;
1578 if ( i+ delta >= cchLen)
1579 return 0;
1581 i += delta;
1583 return chars[i];
1586 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1588 if (i + delta < 0)
1590 if (psa->fLinkBefore)
1591 return jtR;
1592 else
1593 return jtU;
1595 if ( i+ delta >= cchLen)
1597 if (psa->fLinkAfter)
1598 return jtL;
1599 else
1600 return jtU;
1603 i += delta;
1605 if (context_type[i] == jtT)
1606 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1607 else
1608 return context_type[i];
1611 static inline BOOL right_join_causing(CHAR joining_type)
1613 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1616 static inline BOOL left_join_causing(CHAR joining_type)
1618 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1621 static inline BOOL word_break_causing(WCHAR chr)
1623 /* we are working within a string of characters already guareented to
1624 be within one script, Syriac, so we do not worry about any character
1625 other than the space character outside of that range */
1626 return (chr == 0 || chr == 0x20 );
1630 * ContextualShape_Arabic
1632 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1634 CHAR *context_type;
1635 INT *context_shape;
1636 INT dirR, dirL;
1637 int i;
1639 if (*pcGlyphs != cChars)
1641 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1642 return;
1645 if (!psa->fLogicalOrder && psa->fRTL)
1647 dirR = 1;
1648 dirL = -1;
1650 else
1652 dirR = -1;
1653 dirL = 1;
1656 if (!psc->GSUB_Table)
1657 psc->GSUB_Table = load_gsub_table(hdc);
1659 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1660 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1662 for (i = 0; i < cChars; i++)
1663 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1665 for (i = 0; i < cChars; i++)
1667 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1668 context_shape[i] = Xr;
1669 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1670 context_shape[i] = Xl;
1671 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)))
1672 context_shape[i] = Xm;
1673 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1674 context_shape[i] = Xr;
1675 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1676 context_shape[i] = Xl;
1677 else
1678 context_shape[i] = Xn;
1681 /* Contextual Shaping */
1682 i = 0;
1683 while(i < *pcGlyphs)
1685 BOOL shaped = FALSE;
1687 if (psc->GSUB_Table)
1689 INT nextIndex;
1690 INT prevCount = *pcGlyphs;
1691 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1692 if (nextIndex > GSUB_E_NOGLYPH)
1694 i = nextIndex;
1695 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1697 shaped = (nextIndex > GSUB_E_NOGLYPH);
1700 if (!shaped)
1702 if (context_shape[i] == Xn)
1704 WORD newGlyph = pwOutGlyphs[i];
1705 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1707 /* fall back to presentation form B */
1708 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1709 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1710 pwOutGlyphs[i] = newGlyph;
1713 i++;
1717 HeapFree(GetProcessHeap(),0,context_shape);
1718 HeapFree(GetProcessHeap(),0,context_type);
1722 * ContextualShape_Syriac
1725 #define ALAPH 0x710
1726 #define DALATH 0x715
1727 #define RISH 0x72A
1729 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1731 CHAR *context_type;
1732 INT *context_shape;
1733 INT dirR, dirL;
1734 int i;
1736 if (*pcGlyphs != cChars)
1738 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1739 return;
1742 if (!psa->fLogicalOrder && psa->fRTL)
1744 dirR = 1;
1745 dirL = -1;
1747 else
1749 dirR = -1;
1750 dirL = 1;
1753 if (!psc->GSUB_Table)
1754 psc->GSUB_Table = load_gsub_table(hdc);
1756 if (!psc->GSUB_Table)
1757 return;
1759 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1760 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1762 for (i = 0; i < cChars; i++)
1763 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1765 for (i = 0; i < cChars; i++)
1767 if (pwcChars[i] == ALAPH)
1769 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1771 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1772 context_shape[i] = Afj;
1773 else if ( rchar != DALATH && rchar != RISH &&
1774 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1775 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1776 context_shape[i] = Afn;
1777 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1778 context_shape[i] = Afx;
1779 else
1780 context_shape[i] = Xn;
1782 else if (context_type[i] == jtR &&
1783 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1784 context_shape[i] = Xr;
1785 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1786 context_shape[i] = Xl;
1787 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)))
1788 context_shape[i] = Xm;
1789 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1790 context_shape[i] = Xr;
1791 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1792 context_shape[i] = Xl;
1793 else
1794 context_shape[i] = Xn;
1797 /* Contextual Shaping */
1798 i = 0;
1799 while(i < *pcGlyphs)
1801 INT nextIndex;
1802 INT prevCount = *pcGlyphs;
1803 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1804 if (nextIndex > GSUB_E_NOGLYPH)
1806 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1807 i = nextIndex;
1809 else
1810 i++;
1813 HeapFree(GetProcessHeap(),0,context_shape);
1814 HeapFree(GetProcessHeap(),0,context_type);
1818 * ContextualShape_Phags_pa
1821 #define phags_pa_CANDRABINDU 0xA873
1822 #define phags_pa_START 0xA840
1823 #define phags_pa_END 0xA87F
1825 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1827 INT *context_shape;
1828 INT dirR, dirL;
1829 int i;
1831 if (*pcGlyphs != cChars)
1833 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1834 return;
1837 if (!psa->fLogicalOrder && psa->fRTL)
1839 dirR = 1;
1840 dirL = -1;
1842 else
1844 dirR = -1;
1845 dirL = 1;
1848 if (!psc->GSUB_Table)
1849 psc->GSUB_Table = load_gsub_table(hdc);
1851 if (!psc->GSUB_Table)
1852 return;
1854 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1856 for (i = 0; i < cChars; i++)
1858 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1860 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1861 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1862 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1863 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1865 if (jrchar && jlchar)
1866 context_shape[i] = Xm;
1867 else if (jrchar)
1868 context_shape[i] = Xr;
1869 else if (jlchar)
1870 context_shape[i] = Xl;
1871 else
1872 context_shape[i] = Xn;
1874 else
1875 context_shape[i] = -1;
1878 /* Contextual Shaping */
1879 i = 0;
1880 while(i < *pcGlyphs)
1882 if (context_shape[i] >= 0)
1884 INT nextIndex;
1885 INT prevCount = *pcGlyphs;
1886 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1887 if (nextIndex > GSUB_E_NOGLYPH)
1889 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1890 i = nextIndex;
1892 else
1893 i++;
1895 else
1896 i++;
1899 HeapFree(GetProcessHeap(),0,context_shape);
1902 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1904 int i;
1906 /* Replace */
1907 pwOutChars[cWalk] = replacements[0];
1908 cWalk=cWalk+1;
1910 /* Insert */
1911 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1913 int j;
1914 for (j = *pcChars; j > cWalk; j--)
1915 pwOutChars[j] = pwOutChars[j-1];
1916 *pcChars= *pcChars+1;
1917 pwOutChars[cWalk] = replacements[i];
1918 cWalk = cWalk+1;
1922 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1924 int i;
1925 int cWalk;
1927 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1929 for (i = 0; vowels[i].base != 0x0; i++)
1931 if (pwOutChars[cWalk] == vowels[i].base)
1933 int o = 0;
1934 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1935 if (vowels[i].parts[1]) { cWalk++; o++; }
1936 if (vowels[i].parts[2]) { cWalk++; o++; }
1937 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1938 break;
1944 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1946 int i;
1947 int offset = 0;
1948 int cWalk;
1950 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1952 for (i = 0; consonants[i].output!= 0x0; i++)
1954 int j;
1955 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1956 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1957 break;
1959 if (consonants[i].parts[j]==0x0) /* matched all */
1961 int k;
1962 j--;
1963 pwOutChars[cWalk] = consonants[i].output;
1964 for(k = cWalk+1; k < *pcChars - j; k++)
1965 pwOutChars[k] = pwOutChars[k+j];
1966 *pcChars = *pcChars - j;
1967 for (k = j ; k > 0; k--)
1968 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1969 offset += j;
1970 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1971 pwLogClust[k]--;
1972 break;
1975 cWalk++;
1979 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1981 if (s->ralf >= 0)
1983 int j;
1984 WORD Ra = pwChar[s->start];
1985 WORD H = pwChar[s->start+1];
1987 TRACE("Doing reorder of Ra to %i\n",s->base);
1988 for (j = s->start; j < s->base-1; j++)
1989 pwChar[j] = pwChar[j+2];
1990 pwChar[s->base-1] = Ra;
1991 pwChar[s->base] = H;
1993 s->ralf = s->base-1;
1994 s->base -= 2;
1998 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2000 if (s->ralf >= 0)
2002 int j,loc;
2003 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
2004 WORD Ra = pwChar[s->start];
2005 WORD H = pwChar[s->start+1];
2006 for (loc = s->end; loc > stop; loc--)
2007 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
2008 break;
2010 TRACE("Doing reorder of Ra to %i\n",loc);
2011 for (j = s->start; j < loc-1; j++)
2012 pwChar[j] = pwChar[j+2];
2013 pwChar[loc-1] = Ra;
2014 pwChar[loc] = H;
2016 s->ralf = loc-1;
2017 s->base -= 2;
2018 if (s->blwf >= 0) s->blwf -= 2;
2019 if (s->pref >= 0) s->pref -= 2;
2023 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2025 if (s->ralf >= 0)
2027 int j;
2028 WORD Ra = pwChar[s->start];
2029 WORD H = pwChar[s->start+1];
2031 TRACE("Doing reorder of Ra to %i\n",s->end-1);
2032 for (j = s->start; j < s->end-1; j++)
2033 pwChar[j] = pwChar[j+2];
2034 pwChar[s->end-1] = Ra;
2035 pwChar[s->end] = H;
2037 s->ralf = s->end-1;
2038 s->base -= 2;
2039 if (s->blwf >= 0) s->blwf -= 2;
2040 if (s->pref >= 0) s->pref -= 2;
2044 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2046 int i;
2048 /* reorder Matras */
2049 if (s->end > s->base)
2051 for (i = 1; i <= s->end-s->base; i++)
2053 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2055 int j;
2056 WCHAR c = pwChar[s->base+i];
2057 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
2058 for (j = s->base+i; j > s->base; j--)
2059 pwChar[j] = pwChar[j-1];
2060 pwChar[s->base] = c;
2062 if (s->ralf >= s->base) s->ralf++;
2063 if (s->blwf >= s->base) s->blwf++;
2064 if (s->pref >= s->base) s->pref++;
2065 s->base ++;
2071 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2073 int i;
2075 /* reorder Matras */
2076 if (s->end > s->base)
2078 for (i = 1; i <= s->end-s->base; i++)
2080 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2082 int j;
2083 WCHAR c = pwChar[s->base+i];
2084 TRACE("Doing reorder of %x to %i\n",c,s->start);
2085 for (j = s->base+i; j > s->start; j--)
2086 pwChar[j] = pwChar[j-1];
2087 pwChar[s->start] = c;
2089 if (s->ralf >= 0) s->ralf++;
2090 if (s->blwf >= 0) s->blwf++;
2091 if (s->pref >= 0) s->pref++;
2092 s->base ++;
2098 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2100 if (s->blwf >= 0 && g->blwf > g->base)
2102 int j,loc;
2103 int g_offset;
2104 for (loc = s->end; loc > s->blwf; loc--)
2105 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2106 break;
2108 g_offset = (loc - s->blwf) - 1;
2110 if (loc != s->blwf)
2112 WORD blwf = glyphs[g->blwf];
2113 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2114 /* do not care about the pwChar array anymore, just the glyphs */
2115 for (j = 0; j < g_offset; j++)
2116 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2117 glyphs[g->blwf + g_offset] = blwf;
2122 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2124 int i;
2126 /* reorder previously moved Matras to correct position*/
2127 for (i = s->start; i < s->base; i++)
2129 if (lexical(pwChar[i]) == lex_Matra_pre)
2131 int j;
2132 int g_start = g->start + i - s->start;
2133 if (g_start < g->base -1 )
2135 WCHAR og = glyphs[g_start];
2136 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2137 for (j = g_start; j < g->base-1; j++)
2138 glyphs[j] = glyphs[j+1];
2139 glyphs[g->base-1] = og;
2145 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2147 if (s->pref >= 0 && g->pref > g->base)
2149 int j;
2150 WCHAR og = glyphs[g->pref];
2151 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2152 for (j = g->pref; j > g->base; j--)
2153 glyphs[j] = glyphs[j-1];
2154 glyphs[g->base] = og;
2158 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2160 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2161 if (s->start == s->base && s->base == s->end) return;
2162 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2164 Reorder_Ra_follows_base(pwChar, s, lexical);
2165 Reorder_Matra_precede_base(pwChar, s, lexical);
2168 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2170 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2171 if (s->start == s->base && s->base == s->end) return;
2172 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2174 Reorder_Ra_follows_matra(pwChar, s, lexical);
2175 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2178 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2180 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2181 if (s->start == s->base && s->base == s->end) return;
2182 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2184 Reorder_Ra_follows_base(pwChar, s, lexical);
2185 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2188 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2190 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2191 if (s->start == s->base && s->base == s->end) return;
2192 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2194 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2195 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2198 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2200 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2201 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2202 if (s->start == s->base && s->base == s->end) return;
2203 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2205 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2208 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2210 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2211 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2212 if (s->start == s->base && s->base == s->end) return;
2213 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2215 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2216 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2220 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2222 if (shift == 0)
2223 return;
2225 if (glyph_index->start > index)
2226 glyph_index->start += shift;
2227 if (glyph_index->base > index)
2228 glyph_index->base+= shift;
2229 if (glyph_index->end > index)
2230 glyph_index->end+= shift;
2231 if (glyph_index->ralf > index)
2232 glyph_index->ralf+= shift;
2233 if (glyph_index->blwf > index)
2234 glyph_index->blwf+= shift;
2235 if (glyph_index->pref > index)
2236 glyph_index->pref+= shift;
2239 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 )
2241 int index = glyph_index->start;
2243 if (!feature)
2244 return;
2246 while(index <= glyph_index->end)
2248 INT nextIndex;
2249 INT prevCount = *pcGlyphs;
2250 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2251 if (nextIndex > GSUB_E_NOGLYPH)
2253 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2254 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2255 index = nextIndex;
2257 else
2258 index++;
2262 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2264 int i = 0;
2265 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)))))
2266 i++;
2267 if (index + i <= end-1)
2268 return index + i;
2269 else
2270 return -1;
2273 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)
2275 INT index, nextIndex;
2276 INT count,g_offset;
2278 count = syllable->base - syllable->start;
2280 g_offset = 0;
2281 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2282 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2284 INT prevCount = *pcGlyphs;
2285 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2286 if (nextIndex > GSUB_E_NOGLYPH)
2288 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2289 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2290 g_offset += (*pcGlyphs - prevCount);
2293 index+=2;
2294 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2298 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)
2300 INT nextIndex;
2301 INT prevCount = *pcGlyphs;
2303 if (syllable->ralf >= 0)
2305 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2306 if (nextIndex > GSUB_E_NOGLYPH)
2308 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2309 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2314 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2316 int i = 0;
2317 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2318 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2319 is_consonant(lexical(pwChars[index+i+1])))))
2320 i++;
2321 if (index + i <= end-1)
2322 return index+i;
2323 else
2324 return -1;
2327 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)
2329 INT index, nextIndex;
2330 INT count, g_offset=0;
2331 INT ralf = syllable->ralf;
2333 count = syllable->end - syllable->base;
2335 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2337 while (index >= 0)
2339 INT prevCount = *pcGlyphs;
2340 if (ralf >=0 && ralf < index)
2342 g_offset--;
2343 ralf = -1;
2346 if (!modern)
2348 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2349 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2350 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2353 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2354 if (nextIndex > GSUB_E_NOGLYPH)
2356 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2357 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2358 g_offset += (*pcGlyphs - prevCount);
2360 else if (!modern)
2362 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2363 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2364 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2367 index+=2;
2368 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2372 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)
2374 int c;
2375 int overall_shift = 0;
2376 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2377 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2378 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2379 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2380 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2381 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2382 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2383 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2384 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2385 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2386 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2387 IndicSyllable glyph_indexs;
2389 for (c = 0; c < syllable_count; c++)
2391 int old_end;
2392 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2393 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2394 old_end = glyph_indexs.end;
2396 if (locl)
2398 TRACE("applying feature locl\n");
2399 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2401 if (nukt)
2403 TRACE("applying feature nukt\n");
2404 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2406 if (akhn)
2408 TRACE("applying feature akhn\n");
2409 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2412 if (rphf)
2413 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2414 if (rkrf)
2416 TRACE("applying feature rkrf\n");
2417 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2419 if (pref)
2420 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2421 if (blwf)
2423 if (!modern)
2424 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2426 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2429 if (half)
2430 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2431 if (pstf)
2433 TRACE("applying feature pstf\n");
2434 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2436 if (vatu)
2438 TRACE("applying feature vatu\n");
2439 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2441 if (cjct)
2443 TRACE("applying feature cjct\n");
2444 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2447 if (second_reorder)
2448 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2450 overall_shift += glyph_indexs.end - old_end;
2454 static inline int unicode_lex(WCHAR c)
2456 int type;
2458 if (!c) return lex_Generic;
2459 if (c == 0x200D) return lex_ZWJ;
2460 if (c == 0x200C) return lex_ZWNJ;
2461 if (c == 0x00A0) return lex_NBSP;
2463 type = get_table_entry( indic_syllabic_table, c );
2465 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2467 switch( type )
2469 case 0x0d07: /* Unknown */
2470 case 0x0e07: /* Unknwon */
2471 default: return lex_Generic;
2472 case 0x0001:
2473 case 0x0002:
2474 case 0x0011:
2475 case 0x0012:
2476 case 0x0013:
2477 case 0x0014: return lex_Modifier;
2478 case 0x0003:
2479 case 0x0009:
2480 case 0x000a:
2481 case 0x000b:
2482 case 0x000d:
2483 case 0x000e:
2484 case 0x000f:
2485 case 0x0010: return lex_Consonant;
2486 case 0x0004: return lex_Nukta;
2487 case 0x0005: return lex_Halant;
2488 case 0x0006:
2489 case 0x0008: return lex_Vowel;
2490 case 0x0007:
2491 case 0x0107: return lex_Matra_post;
2492 case 0x0207:
2493 case 0x0307: return lex_Matra_pre;
2494 case 0x0807:
2495 case 0x0907:
2496 case 0x0a07:
2497 case 0x0b07:
2498 case 0x0c07:
2499 case 0x0407: return lex_Composed_Vowel;
2500 case 0x0507: return lex_Matra_above;
2501 case 0x0607: return lex_Matra_below;
2502 case 0x000c: return lex_Ra;
2506 static int sinhala_lex(WCHAR c)
2508 switch (c)
2510 case 0x0DDA:
2511 case 0x0DDD:
2512 case 0x0DDC:
2513 case 0x0DDE: return lex_Matra_post;
2514 default:
2515 return unicode_lex(c);
2519 static const VowelComponents Sinhala_vowels[] = {
2520 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2521 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2522 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2523 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2524 {0x0000, {0x0000,0x0000,0x0}}};
2526 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2528 int cCount = cChars;
2529 int i;
2530 WCHAR *input;
2531 IndicSyllable *syllables = NULL;
2532 int syllable_count = 0;
2534 if (*pcGlyphs != cChars)
2536 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2537 return;
2540 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2542 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2544 /* Step 1: Decompose multi part vowels */
2545 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2547 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2549 /* Step 2: Reorder within Syllables */
2550 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2551 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2553 /* Step 3: Strip dangling joiners */
2554 for (i = 0; i < cCount; i++)
2556 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2557 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2558 input[i] = 0x0020;
2561 /* Step 4: Base Form application to syllables */
2562 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2563 *pcGlyphs = cCount;
2564 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2566 HeapFree(GetProcessHeap(),0,input);
2567 HeapFree(GetProcessHeap(),0,syllables);
2570 static int devanagari_lex(WCHAR c)
2572 switch (c)
2574 case 0x0930: return lex_Ra;
2575 default:
2576 return unicode_lex(c);
2580 static const ConsonantComponents Devanagari_consonants[] ={
2581 {{0x0928, 0x093C, 0x00000}, 0x0929},
2582 {{0x0930, 0x093C, 0x00000}, 0x0931},
2583 {{0x0933, 0x093C, 0x00000}, 0x0934},
2584 {{0x0915, 0x093C, 0x00000}, 0x0958},
2585 {{0x0916, 0x093C, 0x00000}, 0x0959},
2586 {{0x0917, 0x093C, 0x00000}, 0x095A},
2587 {{0x091C, 0x093C, 0x00000}, 0x095B},
2588 {{0x0921, 0x093C, 0x00000}, 0x095C},
2589 {{0x0922, 0x093C, 0x00000}, 0x095D},
2590 {{0x092B, 0x093C, 0x00000}, 0x095E},
2591 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2593 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2595 int cCount = cChars;
2596 WCHAR *input;
2597 IndicSyllable *syllables = NULL;
2598 int syllable_count = 0;
2599 BOOL modern = get_GSUB_Indic2(psa, psc);
2601 if (*pcGlyphs != cChars)
2603 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2604 return;
2607 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2608 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2610 /* Step 1: Compose Consonant and Nukta */
2611 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2612 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2614 /* Step 2: Reorder within Syllables */
2615 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2616 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2617 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2618 *pcGlyphs = cCount;
2620 /* Step 3: Base Form application to syllables */
2621 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2623 HeapFree(GetProcessHeap(),0,input);
2624 HeapFree(GetProcessHeap(),0,syllables);
2627 static int bengali_lex(WCHAR c)
2629 switch (c)
2631 case 0x09B0: return lex_Ra;
2632 default:
2633 return unicode_lex(c);
2637 static const VowelComponents Bengali_vowels[] = {
2638 {0x09CB, {0x09C7,0x09BE,0x0000}},
2639 {0x09CC, {0x09C7,0x09D7,0x0000}},
2640 {0x0000, {0x0000,0x0000,0x0000}}};
2642 static const ConsonantComponents Bengali_consonants[] = {
2643 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2644 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2645 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2646 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2647 {{0x0000,0x0000,0x0000}, 0x0000}};
2649 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2651 int cCount = cChars;
2652 WCHAR *input;
2653 IndicSyllable *syllables = NULL;
2654 int syllable_count = 0;
2655 BOOL modern = get_GSUB_Indic2(psa, psc);
2657 if (*pcGlyphs != cChars)
2659 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2660 return;
2663 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2664 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2666 /* Step 1: Decompose Vowels and Compose Consonents */
2667 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2668 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2669 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2671 /* Step 2: Reorder within Syllables */
2672 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2673 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2674 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2675 *pcGlyphs = cCount;
2677 /* Step 3: Initial form is only applied to the beginning of words */
2678 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2680 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2682 int index = cCount;
2683 int gCount = 1;
2684 if (index > 0) index++;
2686 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2690 /* Step 4: Base Form application to syllables */
2691 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2693 HeapFree(GetProcessHeap(),0,input);
2694 HeapFree(GetProcessHeap(),0,syllables);
2697 static int gurmukhi_lex(WCHAR c)
2699 if (c == 0x0A71)
2700 return lex_Modifier;
2701 else
2702 return unicode_lex(c);
2705 static const ConsonantComponents Gurmukhi_consonants[] = {
2706 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2707 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2708 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2709 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2710 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2711 {{0x0000,0x0000,0x0000}, 0x0000}};
2713 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2715 int cCount = cChars;
2716 WCHAR *input;
2717 IndicSyllable *syllables = NULL;
2718 int syllable_count = 0;
2719 BOOL modern = get_GSUB_Indic2(psa, psc);
2721 if (*pcGlyphs != cChars)
2723 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2724 return;
2727 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2728 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2730 /* Step 1: Compose Consonents */
2731 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2732 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2734 /* Step 2: Reorder within Syllables */
2735 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2736 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2737 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2738 *pcGlyphs = cCount;
2740 /* Step 3: Base Form application to syllables */
2741 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2743 HeapFree(GetProcessHeap(),0,input);
2744 HeapFree(GetProcessHeap(),0,syllables);
2747 static int gujarati_lex(WCHAR c)
2749 switch (c)
2751 case 0x0AB0: return lex_Ra;
2752 default:
2753 return unicode_lex(c);
2757 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2759 int cCount = cChars;
2760 WCHAR *input;
2761 IndicSyllable *syllables = NULL;
2762 int syllable_count = 0;
2763 BOOL modern = get_GSUB_Indic2(psa, psc);
2765 if (*pcGlyphs != cChars)
2767 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2768 return;
2771 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2772 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2774 /* Step 1: Reorder within Syllables */
2775 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2776 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2777 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2778 *pcGlyphs = cCount;
2780 /* Step 2: Base Form application to syllables */
2781 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2783 HeapFree(GetProcessHeap(),0,input);
2784 HeapFree(GetProcessHeap(),0,syllables);
2787 static int oriya_lex(WCHAR c)
2789 switch (c)
2791 case 0x0B30: return lex_Ra;
2792 default:
2793 return unicode_lex(c);
2797 static const VowelComponents Oriya_vowels[] = {
2798 {0x0B48, {0x0B47,0x0B56,0x0000}},
2799 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2800 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2801 {0x0000, {0x0000,0x0000,0x0000}}};
2803 static const ConsonantComponents Oriya_consonants[] = {
2804 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2805 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2806 {{0x0000,0x0000,0x0000}, 0x0000}};
2808 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2810 int cCount = cChars;
2811 WCHAR *input;
2812 IndicSyllable *syllables = NULL;
2813 int syllable_count = 0;
2814 BOOL modern = get_GSUB_Indic2(psa, psc);
2816 if (*pcGlyphs != cChars)
2818 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2819 return;
2822 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2823 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2825 /* Step 1: Decompose Vowels and Compose Consonents */
2826 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2827 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2828 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2830 /* Step 2: Reorder within Syllables */
2831 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2832 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2833 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2834 *pcGlyphs = cCount;
2836 /* Step 3: Base Form application to syllables */
2837 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2839 HeapFree(GetProcessHeap(),0,input);
2840 HeapFree(GetProcessHeap(),0,syllables);
2843 static int tamil_lex(WCHAR c)
2845 return unicode_lex(c);
2848 static const VowelComponents Tamil_vowels[] = {
2849 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2850 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2851 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2852 {0x0000, {0x0000,0x0000,0x0000}}};
2854 static const ConsonantComponents Tamil_consonants[] = {
2855 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2856 {{0x0000,0x0000,0x0000}, 0x0000}};
2858 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2860 int cCount = cChars;
2861 WCHAR *input;
2862 IndicSyllable *syllables = NULL;
2863 int syllable_count = 0;
2864 BOOL modern = get_GSUB_Indic2(psa, psc);
2866 if (*pcGlyphs != cChars)
2868 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2869 return;
2872 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2873 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2875 /* Step 1: Decompose Vowels and Compose Consonents */
2876 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2877 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2878 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2880 /* Step 2: Reorder within Syllables */
2881 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2882 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2883 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2884 *pcGlyphs = cCount;
2886 /* Step 3: Base Form application to syllables */
2887 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2889 HeapFree(GetProcessHeap(),0,input);
2890 HeapFree(GetProcessHeap(),0,syllables);
2893 static int telugu_lex(WCHAR c)
2895 switch (c)
2897 case 0x0C43:
2898 case 0x0C44: return lex_Modifier;
2899 default:
2900 return unicode_lex(c);
2904 static const VowelComponents Telugu_vowels[] = {
2905 {0x0C48, {0x0C46,0x0C56,0x0000}},
2906 {0x0000, {0x0000,0x0000,0x0000}}};
2908 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2910 int cCount = cChars;
2911 WCHAR *input;
2912 IndicSyllable *syllables = NULL;
2913 int syllable_count = 0;
2914 BOOL modern = get_GSUB_Indic2(psa, psc);
2916 if (*pcGlyphs != cChars)
2918 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2919 return;
2922 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2923 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2925 /* Step 1: Decompose Vowels */
2926 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2927 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2929 /* Step 2: Reorder within Syllables */
2930 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2931 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2932 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2933 *pcGlyphs = cCount;
2935 /* Step 3: Base Form application to syllables */
2936 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2938 HeapFree(GetProcessHeap(),0,input);
2939 HeapFree(GetProcessHeap(),0,syllables);
2942 static int kannada_lex(WCHAR c)
2944 switch (c)
2946 case 0x0CB0: return lex_Ra;
2947 default:
2948 return unicode_lex(c);
2952 static const VowelComponents Kannada_vowels[] = {
2953 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2954 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2955 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2956 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2957 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2958 {0x0000, {0x0000,0x0000,0x0000}}};
2960 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2962 int cCount = cChars;
2963 WCHAR *input;
2964 IndicSyllable *syllables = NULL;
2965 int syllable_count = 0;
2966 BOOL modern = get_GSUB_Indic2(psa, psc);
2968 if (*pcGlyphs != cChars)
2970 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2971 return;
2974 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2975 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2977 /* Step 1: Decompose Vowels */
2978 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2979 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2981 /* Step 2: Reorder within Syllables */
2982 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2983 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2984 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2985 *pcGlyphs = cCount;
2987 /* Step 3: Base Form application to syllables */
2988 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2990 HeapFree(GetProcessHeap(),0,input);
2991 HeapFree(GetProcessHeap(),0,syllables);
2994 static int malayalam_lex(WCHAR c)
2996 return unicode_lex(c);
2999 static const VowelComponents Malayalam_vowels[] = {
3000 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
3001 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
3002 {0x0D4C, {0x0D46,0x0D57,0x0000}},
3003 {0x0000, {0x0000,0x0000,0x0000}}};
3005 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3007 int cCount = cChars;
3008 WCHAR *input;
3009 IndicSyllable *syllables = NULL;
3010 int syllable_count = 0;
3011 BOOL modern = get_GSUB_Indic2(psa, psc);
3013 if (*pcGlyphs != cChars)
3015 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3016 return;
3019 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
3020 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3022 /* Step 1: Decompose Vowels */
3023 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
3024 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
3026 /* Step 2: Reorder within Syllables */
3027 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
3028 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3029 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3030 *pcGlyphs = cCount;
3032 /* Step 3: Base Form application to syllables */
3033 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
3035 HeapFree(GetProcessHeap(),0,input);
3036 HeapFree(GetProcessHeap(),0,syllables);
3039 static int khmer_lex(WCHAR c)
3041 return unicode_lex(c);
3044 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3046 int cCount = cChars;
3047 WCHAR *input;
3048 IndicSyllable *syllables = NULL;
3049 int syllable_count = 0;
3051 if (*pcGlyphs != cChars)
3053 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3054 return;
3057 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
3058 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3060 /* Step 1: Reorder within Syllables */
3061 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
3062 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3063 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3064 *pcGlyphs = cCount;
3066 /* Step 2: Base Form application to syllables */
3067 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
3069 HeapFree(GetProcessHeap(),0,input);
3070 HeapFree(GetProcessHeap(),0,syllables);
3073 static inline BOOL mongolian_wordbreak(WCHAR chr)
3075 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
3078 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3080 INT *context_shape;
3081 INT dirL;
3082 int i;
3084 if (*pcGlyphs != cChars)
3086 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3087 return;
3090 if (!psa->fLogicalOrder && psa->fRTL)
3091 dirL = -1;
3092 else
3093 dirL = 1;
3095 if (!psc->GSUB_Table)
3096 psc->GSUB_Table = load_gsub_table(hdc);
3098 if (!psc->GSUB_Table)
3099 return;
3101 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
3103 for (i = 0; i < cChars; i++)
3105 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
3107 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
3108 context_shape[i] = Xn;
3109 else
3110 context_shape[i] = Xl;
3112 else
3114 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
3115 context_shape[i] = Xr;
3116 else
3117 context_shape[i] = Xm;
3121 /* Contextual Shaping */
3122 i = 0;
3123 while(i < *pcGlyphs)
3125 INT nextIndex;
3126 INT prevCount = *pcGlyphs;
3127 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
3128 if (nextIndex > GSUB_E_NOGLYPH)
3130 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
3131 i = nextIndex;
3133 else
3134 i++;
3137 HeapFree(GetProcessHeap(),0,context_shape);
3140 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)
3142 int i,k;
3144 for (i = 0; i < cGlyphs; i++)
3146 int char_index[20];
3147 int char_count = 0;
3149 for (k = 0; k < cChars; k++)
3151 if (pwLogClust[k] == i)
3153 char_index[char_count] = k;
3154 char_count++;
3158 if (char_count == 0)
3159 continue;
3161 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3163 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3164 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3166 else
3167 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3170 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3171 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3174 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 )
3176 int i,k;
3177 int initGlyph, finaGlyph;
3178 INT dirR, dirL;
3179 BYTE *spaces;
3181 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3182 memset(spaces,0,cGlyphs);
3184 if (!psa->fLogicalOrder && psa->fRTL)
3186 initGlyph = cGlyphs-1;
3187 finaGlyph = 0;
3188 dirR = 1;
3189 dirL = -1;
3191 else
3193 initGlyph = 0;
3194 finaGlyph = cGlyphs-1;
3195 dirR = -1;
3196 dirL = 1;
3199 for (i = 0; i < cGlyphs; i++)
3201 for (k = 0; k < cChars; k++)
3202 if (pwLogClust[k] == i)
3204 if (pwcChars[k] == 0x0020)
3205 spaces[i] = 1;
3209 for (i = 0; i < cGlyphs; i++)
3211 int char_index[20];
3212 int char_count = 0;
3213 BOOL isInit, isFinal;
3215 for (k = 0; k < cChars; k++)
3217 if (pwLogClust[k] == i)
3219 char_index[char_count] = k;
3220 char_count++;
3224 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3225 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3227 if (char_count == 0)
3228 continue;
3230 if (char_count == 1)
3232 if (pwcChars[char_index[0]] == 0x0020) /* space */
3234 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3235 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3237 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3238 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3239 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3241 if (!isInit && !isFinal)
3242 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3243 else if (isInit)
3244 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3245 else
3246 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3248 else if (!isInit)
3250 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3251 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3252 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3253 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3254 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3255 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3256 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3257 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3258 else
3259 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3261 else if (!isInit && !isFinal)
3262 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3263 else
3264 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3266 else if (char_count == 2)
3268 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3269 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3270 else if (!isInit)
3271 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3272 else
3273 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3275 else if (!isInit && !isFinal)
3276 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3277 else
3278 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3281 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3282 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3283 HeapFree(GetProcessHeap(),0,spaces);
3286 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 )
3288 int i,k;
3289 int finaGlyph;
3290 INT dirL;
3291 BYTE *spaces;
3293 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3294 memset(spaces,0,cGlyphs);
3296 if (!psa->fLogicalOrder && psa->fRTL)
3298 finaGlyph = 0;
3299 dirL = -1;
3301 else
3303 finaGlyph = cGlyphs-1;
3304 dirL = 1;
3307 for (i = 0; i < cGlyphs; i++)
3309 for (k = 0; k < cChars; k++)
3310 if (pwLogClust[k] == i)
3312 if (pwcChars[k] == 0x0020)
3313 spaces[i] = 1;
3317 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3319 for (i = 0; i < cGlyphs; i++)
3321 int char_index[20];
3322 int char_count = 0;
3324 for (k = 0; k < cChars; k++)
3326 if (pwLogClust[k] == i)
3328 char_index[char_count] = k;
3329 char_count++;
3333 if (char_count == 0)
3334 continue;
3336 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3338 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3339 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3341 else if (i == finaGlyph)
3342 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3343 else
3344 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3346 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3347 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3348 pGlyphProp[i].sva.fClusterStart = 0;
3351 HeapFree(GetProcessHeap(),0,spaces);
3352 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3354 /* Do not allow justification between marks and their base */
3355 for (i = 0; i < cGlyphs; i++)
3357 if (!pGlyphProp[i].sva.fClusterStart)
3358 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3362 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)
3364 int i,k;
3366 for (i = 0; i < cGlyphs; i++)
3368 int char_index[20];
3369 int char_count = 0;
3371 for (k = 0; k < cChars; k++)
3373 if (pwLogClust[k] == i)
3375 char_index[char_count] = k;
3376 char_count++;
3380 if (char_count == 0)
3381 continue;
3383 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3385 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3386 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3388 else
3389 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3391 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3392 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3395 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)
3397 int i,k;
3399 for (i = 0; i < cGlyphs; i++)
3401 int char_index[20];
3402 int char_count = 0;
3404 for (k = 0; k < cChars; k++)
3406 if (pwLogClust[k] == i)
3408 char_index[char_count] = k;
3409 char_count++;
3413 if (char_count == 0)
3414 continue;
3416 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3418 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3419 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3421 else
3422 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3424 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3425 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3427 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3428 for (i = 0; i < cGlyphs; i++)
3430 if (!pGlyphProp[i].sva.fClusterStart)
3432 pGlyphProp[i].sva.fDiacritic = 0;
3433 pGlyphProp[i].sva.fZeroWidth = 0;
3438 static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables, BOOL override_gsub)
3440 int i,k;
3442 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3443 for (i = 0; i < cGlyphs; i++)
3445 int char_index[20];
3446 int char_count = 0;
3448 for (k = 0; k < cChars; k++)
3450 if (pwLogClust[k] == i)
3452 char_index[char_count] = k;
3453 char_count++;
3457 if (override_gsub)
3459 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3460 pGlyphProp[i].sva.fDiacritic = FALSE;
3461 pGlyphProp[i].sva.fZeroWidth = FALSE;
3464 if (char_count == 0)
3465 continue;
3467 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3469 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3470 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3472 else
3473 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3475 pGlyphProp[i].sva.fClusterStart = 0;
3476 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3477 switch (lexical(pwcChars[char_index[k]]))
3479 case lex_Matra_pre:
3480 case lex_Matra_post:
3481 case lex_Matra_above:
3482 case lex_Matra_below:
3483 case lex_Modifier:
3484 case lex_Halant:
3485 break;
3486 case lex_ZWJ:
3487 case lex_ZWNJ:
3488 /* check for dangling joiners */
3489 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3490 pGlyphProp[i].sva.fClusterStart = 1;
3491 else
3492 k = char_count;
3493 break;
3494 default:
3495 pGlyphProp[i].sva.fClusterStart = 1;
3496 break;
3500 if (use_syllables)
3502 IndicSyllable *syllables = NULL;
3503 int syllable_count = 0;
3504 BOOL modern = get_GSUB_Indic2(psa, psc);
3506 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3508 for (i = 0; i < syllable_count; i++)
3510 int j;
3511 WORD g = pwLogClust[syllables[i].start];
3512 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3514 if (pwLogClust[j] != g)
3516 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3517 pwLogClust[j] = g;
3522 HeapFree(GetProcessHeap(), 0, syllables);
3525 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3528 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3530 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3533 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 )
3535 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3538 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 )
3540 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3543 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 )
3545 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3548 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 )
3550 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3553 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 )
3555 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3558 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 )
3560 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3563 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 )
3565 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3568 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 )
3570 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3573 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 )
3575 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3578 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3580 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3583 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)
3585 if (ShapingData[psa->eScript].charGlyphPropProc)
3586 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3587 else
3588 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3591 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3593 if (!psc->GSUB_Table)
3594 psc->GSUB_Table = load_gsub_table(hdc);
3596 if (ShapingData[psa->eScript].contextProc)
3597 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3600 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)
3602 int i;
3603 INT dirL;
3605 if (!rpRangeProperties)
3606 return;
3608 if (!psc->GSUB_Table)
3609 psc->GSUB_Table = load_gsub_table(hdc);
3611 if (!psc->GSUB_Table)
3612 return;
3614 if (!psa->fLogicalOrder && psa->fRTL)
3615 dirL = -1;
3616 else
3617 dirL = 1;
3619 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3621 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3622 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3626 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3628 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3629 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3631 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3634 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3636 const GSUB_Feature *feature;
3637 int i;
3639 if (!ShapingData[psa->eScript].requiredFeatures)
3640 return S_OK;
3642 if (!psc->GSUB_Table)
3643 psc->GSUB_Table = load_gsub_table(hdc);
3645 /* we need to have at least one of the required features */
3646 i = 0;
3647 while (ShapingData[psa->eScript].requiredFeatures[i])
3649 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3650 if (feature)
3651 return S_OK;
3652 i++;
3655 return USP_E_SCRIPT_NOT_IN_FONT;