usp10: Add Braille script.
[wine/multimedia.git] / dlls / usp10 / shape.c
blob008d2cfc32ce608390d46e9e6bf685837ae78d3d
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},
680 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
682 const GSUB_CoverageFormat1* cf1;
684 cf1 = table;
686 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
688 int count = GET_BE_WORD(cf1->GlyphCount);
689 int i;
690 TRACE("Coverage Format 1, %i glyphs\n",count);
691 for (i = 0; i < count; i++)
692 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
693 return i;
694 return -1;
696 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
698 const GSUB_CoverageFormat2* cf2;
699 int i;
700 int count;
701 cf2 = (const GSUB_CoverageFormat2*)cf1;
703 count = GET_BE_WORD(cf2->RangeCount);
704 TRACE("Coverage Format 2, %i ranges\n",count);
705 for (i = 0; i < count; i++)
707 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
708 return -1;
709 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
710 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
712 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
713 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
716 return -1;
718 else
719 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
721 return -1;
724 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
726 const GSUB_ScriptList *script;
727 const GSUB_Script *deflt = NULL;
728 int i;
729 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
731 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
732 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
734 const GSUB_Script *scr;
735 int offset;
737 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
738 scr = (const GSUB_Script*)((const BYTE*)script + offset);
740 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
741 return scr;
742 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
743 deflt = scr;
745 return deflt;
748 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
750 int i;
751 int offset;
752 const GSUB_LangSys *Lang;
754 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
756 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
758 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
759 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
761 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
762 return Lang;
764 offset = GET_BE_WORD(script->DefaultLangSys);
765 if (offset)
767 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
768 return Lang;
770 return NULL;
773 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
775 int i;
776 const GSUB_FeatureList *feature;
777 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
779 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
780 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
782 int index = GET_BE_WORD(lang->FeatureIndex[i]);
783 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
785 const GSUB_Feature *feat;
786 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
787 return feat;
790 return NULL;
793 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
795 int j;
796 TRACE("Single Substitution Subtable\n");
798 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
800 int offset;
801 const GSUB_SingleSubstFormat1 *ssf1;
802 offset = GET_BE_WORD(look->SubTable[j]);
803 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
804 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
806 int offset = GET_BE_WORD(ssf1->Coverage);
807 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
808 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
810 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
811 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
812 TRACE(" 0x%x\n",glyphs[glyph_index]);
813 return glyph_index + write_dir;
816 else
818 const GSUB_SingleSubstFormat2 *ssf2;
819 INT index;
820 INT offset;
822 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
823 offset = GET_BE_WORD(ssf1->Coverage);
824 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
825 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
826 TRACE(" Coverage index %i\n",index);
827 if (index != -1)
829 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
830 return GSUB_E_NOGLYPH;
832 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
833 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
834 TRACE("0x%x\n",glyphs[glyph_index]);
835 return glyph_index + write_dir;
839 return GSUB_E_NOGLYPH;
842 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
844 int j;
845 TRACE("Multiple Substitution Subtable\n");
847 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
849 int offset, index;
850 const GSUB_MultipleSubstFormat1 *msf1;
851 offset = GET_BE_WORD(look->SubTable[j]);
852 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
854 offset = GET_BE_WORD(msf1->Coverage);
855 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
856 if (index != -1)
858 const GSUB_Sequence *seq;
859 int sub_count;
860 int j;
861 offset = GET_BE_WORD(msf1->Sequence[index]);
862 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
863 sub_count = GET_BE_WORD(seq->GlyphCount);
864 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
866 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
867 glyphs[j] =glyphs[j-(sub_count-1)];
869 for (j = 0; j < sub_count; j++)
870 if (write_dir < 0)
871 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
872 else
873 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
875 *glyph_count = *glyph_count + (sub_count - 1);
877 if (TRACE_ON(uniscribe))
879 for (j = 0; j < sub_count; j++)
880 TRACE(" 0x%x",glyphs[glyph_index+j]);
881 TRACE("\n");
884 return glyph_index + (sub_count * write_dir);
887 return GSUB_E_NOGLYPH;
890 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
892 int j;
893 TRACE("Alternate Substitution Subtable\n");
895 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
897 int offset;
898 const GSUB_AlternateSubstFormat1 *asf1;
899 INT index;
901 offset = GET_BE_WORD(look->SubTable[j]);
902 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
903 offset = GET_BE_WORD(asf1->Coverage);
905 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
906 if (index != -1)
908 const GSUB_AlternateSet *as;
909 offset = GET_BE_WORD(asf1->AlternateSet[index]);
910 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
911 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
912 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
913 return GSUB_E_NOGLYPH;
915 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
916 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
917 TRACE(" 0x%x\n",glyphs[glyph_index]);
918 return glyph_index + write_dir;
921 return GSUB_E_NOGLYPH;
924 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
926 int j;
928 TRACE("Ligature Substitution Subtable\n");
929 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
931 const GSUB_LigatureSubstFormat1 *lsf1;
932 int offset,index;
934 offset = GET_BE_WORD(look->SubTable[j]);
935 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
936 offset = GET_BE_WORD(lsf1->Coverage);
937 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
938 TRACE(" Coverage index %i\n",index);
939 if (index != -1)
941 const GSUB_LigatureSet *ls;
942 int k, count;
944 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
945 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
946 count = GET_BE_WORD(ls->LigatureCount);
947 TRACE(" LigatureSet has %i members\n",count);
948 for (k = 0; k < count; k++)
950 const GSUB_Ligature *lig;
951 int CompCount,l,CompIndex;
953 offset = GET_BE_WORD(ls->Ligature[k]);
954 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
955 CompCount = GET_BE_WORD(lig->CompCount) - 1;
956 CompIndex = glyph_index+write_dir;
957 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
959 int CompGlyph;
960 CompGlyph = GET_BE_WORD(lig->Component[l]);
961 if (CompGlyph != glyphs[CompIndex])
962 break;
963 CompIndex += write_dir;
965 if (l == CompCount)
967 int replaceIdx = glyph_index;
968 if (write_dir < 0)
969 replaceIdx = glyph_index - CompCount;
971 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
972 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
973 TRACE("0x%x\n",glyphs[replaceIdx]);
974 if (CompCount > 0)
976 int j;
977 for (j = replaceIdx + 1; j < *glyph_count; j++)
978 glyphs[j] =glyphs[j+CompCount];
979 *glyph_count = *glyph_count - CompCount;
981 return replaceIdx + write_dir;
986 return GSUB_E_NOGLYPH;
989 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
991 int j;
992 BOOL done = FALSE;
994 TRACE("Chaining Contextual Substitution Subtable\n");
995 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
997 const GSUB_ChainContextSubstFormat1 *ccsf1;
998 int offset;
999 int dirLookahead = write_dir;
1000 int dirBacktrack = -1 * write_dir;
1002 offset = GET_BE_WORD(look->SubTable[j]);
1003 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
1004 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
1006 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
1007 continue;
1009 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
1011 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
1012 continue;
1014 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
1016 int k;
1017 int indexGlyphs;
1018 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
1019 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
1020 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
1021 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
1022 int newIndex = glyph_index;
1024 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
1026 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
1028 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
1030 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
1031 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
1032 break;
1034 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
1035 continue;
1036 TRACE("Matched Backtrack\n");
1038 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
1040 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
1041 for (k = 0; k < indexGlyphs; k++)
1043 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
1044 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
1045 break;
1047 if (k != indexGlyphs)
1048 continue;
1049 TRACE("Matched IndexGlyphs\n");
1051 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
1053 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
1055 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
1056 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
1057 break;
1059 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
1060 continue;
1061 TRACE("Matched LookAhead\n");
1063 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
1065 if (GET_BE_WORD(ccsf3_4->SubstCount))
1067 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
1069 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
1070 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
1072 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1073 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
1074 if (newIndex == -1)
1076 ERR("Chain failed to generate a glyph\n");
1077 continue;
1080 return newIndex;
1082 else return GSUB_E_NOGLYPH;
1085 return -1;
1088 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1090 int offset;
1091 const GSUB_LookupTable *look;
1093 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1094 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1095 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1096 switch(GET_BE_WORD(look->LookupType))
1098 case 1:
1099 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1100 case 2:
1101 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1102 case 3:
1103 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1104 case 4:
1105 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1106 case 6:
1107 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1108 default:
1109 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1111 return GSUB_E_NOGLYPH;
1114 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)
1116 int i;
1117 int out_index = GSUB_E_NOGLYPH;
1118 const GSUB_LookupList *lookup;
1120 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1122 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1123 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1125 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1126 if (out_index != GSUB_E_NOGLYPH)
1127 break;
1129 if (out_index == GSUB_E_NOGLYPH)
1130 TRACE("lookups found no glyphs\n");
1131 else
1133 int out2;
1134 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1135 if (out2!=GSUB_E_NOGLYPH)
1136 out_index = out2;
1138 return out_index;
1141 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1143 UINT charset;
1145 if (psc->userScript != 0)
1147 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1148 return ShapingData[psa->eScript].newOtTag;
1149 else
1150 return (char*)&psc->userScript;
1153 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1154 return ShapingData[psa->eScript].newOtTag;
1156 if (ShapingData[psa->eScript].otTag[0] != 0)
1157 return ShapingData[psa->eScript].otTag;
1160 * fall back to the font charset
1162 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1163 switch (charset)
1165 case ANSI_CHARSET: return "latn";
1166 case BALTIC_CHARSET: return "latn"; /* ?? */
1167 case CHINESEBIG5_CHARSET: return "hani";
1168 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1169 case GB2312_CHARSET: return "hani";
1170 case GREEK_CHARSET: return "grek";
1171 case HANGUL_CHARSET: return "hang";
1172 case RUSSIAN_CHARSET: return "cyrl";
1173 case SHIFTJIS_CHARSET: return "kana";
1174 case TURKISH_CHARSET: return "latn"; /* ?? */
1175 case VIETNAMESE_CHARSET: return "latn";
1176 case JOHAB_CHARSET: return "latn"; /* ?? */
1177 case ARABIC_CHARSET: return "arab";
1178 case HEBREW_CHARSET: return "hebr";
1179 case THAI_CHARSET: return "thai";
1180 default: return "latn";
1184 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1186 const GSUB_Feature *feature;
1187 const char* script;
1188 int i;
1190 script = get_opentype_script(hdc,psa,psc,FALSE);
1192 for (i = 0; i < psc->feature_count; i++)
1194 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1195 return psc->features[i].feature;
1198 feature = NULL;
1200 if (psc->GSUB_Table)
1202 const GSUB_Script *script;
1203 const GSUB_LangSys *language;
1204 int attempt = 2;
1208 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1209 attempt--;
1210 if (script)
1212 if (psc->userLang != 0)
1213 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1214 else
1215 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1216 if (language)
1217 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1219 } while(attempt && !feature);
1221 /* try in the default (latin) table */
1222 if (!feature)
1224 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1225 if (script)
1227 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1228 if (language)
1229 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1234 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1236 psc->feature_count++;
1238 if (psc->features)
1239 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1240 else
1241 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1243 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1244 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1245 psc->features[psc->feature_count - 1].feature = feature;
1246 return feature;
1249 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)
1251 const GSUB_Feature *feature;
1253 feature = load_GSUB_feature(hdc, psa, psc, feat);
1254 if (!feature)
1255 return GSUB_E_NOFEATURE;
1257 TRACE("applying feature %s\n",feat);
1258 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1261 static VOID *load_gsub_table(HDC hdc)
1263 VOID* GSUB_Table = NULL;
1264 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1265 if (length != GDI_ERROR)
1267 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1268 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1269 TRACE("Loaded GSUB table of %i bytes\n",length);
1271 return GSUB_Table;
1274 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)
1276 WORD *glyphs;
1277 INT glyph_count = count;
1278 INT rc;
1280 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1281 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1282 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1283 if (rc > GSUB_E_NOGLYPH)
1284 rc = count - glyph_count;
1285 else
1286 rc = 0;
1288 HeapFree(GetProcessHeap(),0,glyphs);
1289 return rc;
1292 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1294 int offset;
1295 WORD class = 0;
1296 const GDEF_ClassDefFormat1 *cf1;
1298 if (!header)
1299 return 0;
1301 offset = GET_BE_WORD(header->GlyphClassDef);
1302 if (!offset)
1303 return 0;
1305 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1306 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1308 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1310 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1311 if (index < GET_BE_WORD(cf1->GlyphCount))
1312 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1315 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1317 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1318 int i, top;
1319 top = GET_BE_WORD(cf2->ClassRangeCount);
1320 for (i = 0; i < top; i++)
1322 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1323 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1325 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1326 break;
1330 else
1331 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1333 return class;
1336 static VOID *load_gdef_table(HDC hdc)
1338 VOID* GDEF_Table = NULL;
1339 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1340 if (length != GDI_ERROR)
1342 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1343 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1344 TRACE("Loaded GDEF table of %i bytes\n",length);
1346 return GDEF_Table;
1349 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
1351 int i;
1353 if (!psc->GDEF_Table)
1354 psc->GDEF_Table = load_gdef_table(hdc);
1356 for (i = 0; i < cGlyphs; i++)
1358 WORD class;
1359 int char_count = 0;
1360 int k;
1362 for (k = 0; k < cChars; k++)
1363 if (pwLogClust[k] == i)
1364 char_count++;
1366 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1368 switch (class)
1370 case 0:
1371 case BaseGlyph:
1372 pGlyphProp[i].sva.fClusterStart = 1;
1373 pGlyphProp[i].sva.fDiacritic = 0;
1374 pGlyphProp[i].sva.fZeroWidth = 0;
1375 break;
1376 case LigatureGlyph:
1377 pGlyphProp[i].sva.fClusterStart = 1;
1378 pGlyphProp[i].sva.fDiacritic = 0;
1379 pGlyphProp[i].sva.fZeroWidth = 0;
1380 break;
1381 case MarkGlyph:
1382 pGlyphProp[i].sva.fClusterStart = 0;
1383 pGlyphProp[i].sva.fDiacritic = 1;
1384 pGlyphProp[i].sva.fZeroWidth = 1;
1385 break;
1386 case ComponentGlyph:
1387 pGlyphProp[i].sva.fClusterStart = 0;
1388 pGlyphProp[i].sva.fDiacritic = 0;
1389 pGlyphProp[i].sva.fZeroWidth = 0;
1390 break;
1391 default:
1392 ERR("Unknown glyph class %i\n",class);
1393 pGlyphProp[i].sva.fClusterStart = 1;
1394 pGlyphProp[i].sva.fDiacritic = 0;
1395 pGlyphProp[i].sva.fZeroWidth = 0;
1398 if (char_count == 0)
1399 pGlyphProp[i].sva.fClusterStart = 0;
1403 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1405 int i;
1407 for (i = 0; i < cGlyphs; i++)
1409 if (!pGlyphProp[i].sva.fClusterStart)
1411 int j;
1412 for (j = 0; j < cChars; j++)
1414 if (pwLogClust[j] == i)
1416 int k = j;
1417 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1418 k-=1;
1419 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1420 pwLogClust[j] = pwLogClust[k];
1427 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1429 if (changeCount == 0)
1430 return;
1431 else
1433 int i;
1434 int target_glyph = nextIndex - write_dir;
1435 int seeking_glyph;
1436 int target_index = -1;
1437 int replacing_glyph = -1;
1438 int changed = 0;
1439 int top_logclust = 0;
1441 if (changeCount > 0)
1443 if (write_dir > 0)
1444 target_glyph = nextIndex - changeCount;
1445 else
1446 target_glyph = nextIndex + (changeCount + 1);
1449 seeking_glyph = target_glyph;
1450 for (i = 0; i < chars; i++)
1451 if (pwLogClust[i] > top_logclust)
1452 top_logclust = pwLogClust[i];
1454 do {
1455 if (write_dir > 0)
1456 for (i = 0; i < chars; i++)
1458 if (pwLogClust[i] == seeking_glyph)
1460 target_index = i;
1461 break;
1464 else
1465 for (i = chars - 1; i >= 0; i--)
1467 if (pwLogClust[i] == seeking_glyph)
1469 target_index = i;
1470 break;
1473 if (target_index == -1)
1474 seeking_glyph ++;
1476 while (target_index == -1 && seeking_glyph <= top_logclust);
1478 if (target_index == -1)
1480 ERR("Unable to find target glyph\n");
1481 return;
1484 if (changeCount < 0)
1486 /* merge glyphs */
1487 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1489 if (pwLogClust[i] == target_glyph)
1490 continue;
1491 if(pwLogClust[i] == replacing_glyph)
1492 pwLogClust[i] = target_glyph;
1493 else
1495 changed--;
1496 if (changed >= changeCount)
1498 replacing_glyph = pwLogClust[i];
1499 pwLogClust[i] = target_glyph;
1501 else
1502 break;
1506 /* renumber trailing indexes*/
1507 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1509 if (pwLogClust[i] != target_glyph)
1510 pwLogClust[i] += changeCount;
1513 else
1515 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1516 pwLogClust[i] += changeCount;
1521 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 )
1523 if (psc->GSUB_Table)
1525 const GSUB_Feature *feature;
1526 const GSUB_LookupList *lookup;
1527 const GSUB_Header *header = psc->GSUB_Table;
1528 int lookup_index, lookup_count;
1530 feature = load_GSUB_feature(hdc, psa, psc, feat);
1531 if (!feature)
1532 return GSUB_E_NOFEATURE;
1534 TRACE("applying feature %s\n",debugstr_an(feat,4));
1535 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1536 lookup_count = GET_BE_WORD(feature->LookupCount);
1537 TRACE("%i lookups\n", lookup_count);
1538 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1540 int i;
1542 if (write_dir > 0)
1543 i = 0;
1544 else
1545 i = *pcGlyphs-1;
1546 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1547 while(i < *pcGlyphs && i >= 0)
1549 INT nextIndex;
1550 INT prevCount = *pcGlyphs;
1552 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1553 if (*pcGlyphs != prevCount)
1555 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1556 i = nextIndex;
1558 else
1559 i+=write_dir;
1562 return *pcGlyphs;
1564 return GSUB_E_NOFEATURE;
1567 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1569 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1572 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1574 if (i + delta < 0)
1575 return 0;
1576 if ( i+ delta >= cchLen)
1577 return 0;
1579 i += delta;
1581 return chars[i];
1584 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1586 if (i + delta < 0)
1588 if (psa->fLinkBefore)
1589 return jtR;
1590 else
1591 return jtU;
1593 if ( i+ delta >= cchLen)
1595 if (psa->fLinkAfter)
1596 return jtL;
1597 else
1598 return jtU;
1601 i += delta;
1603 if (context_type[i] == jtT)
1604 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1605 else
1606 return context_type[i];
1609 static inline BOOL right_join_causing(CHAR joining_type)
1611 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1614 static inline BOOL left_join_causing(CHAR joining_type)
1616 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1619 static inline BOOL word_break_causing(WCHAR chr)
1621 /* we are working within a string of characters already guareented to
1622 be within one script, Syriac, so we do not worry about any character
1623 other than the space character outside of that range */
1624 return (chr == 0 || chr == 0x20 );
1628 * ContextualShape_Arabic
1630 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1632 CHAR *context_type;
1633 INT *context_shape;
1634 INT dirR, dirL;
1635 int i;
1637 if (*pcGlyphs != cChars)
1639 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1640 return;
1643 if (!psa->fLogicalOrder && psa->fRTL)
1645 dirR = 1;
1646 dirL = -1;
1648 else
1650 dirR = -1;
1651 dirL = 1;
1654 if (!psc->GSUB_Table)
1655 psc->GSUB_Table = load_gsub_table(hdc);
1657 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1658 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1660 for (i = 0; i < cChars; i++)
1661 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1663 for (i = 0; i < cChars; i++)
1665 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1666 context_shape[i] = Xr;
1667 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1668 context_shape[i] = Xl;
1669 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)))
1670 context_shape[i] = Xm;
1671 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1672 context_shape[i] = Xr;
1673 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1674 context_shape[i] = Xl;
1675 else
1676 context_shape[i] = Xn;
1679 /* Contextual Shaping */
1680 i = 0;
1681 while(i < *pcGlyphs)
1683 BOOL shaped = FALSE;
1685 if (psc->GSUB_Table)
1687 INT nextIndex;
1688 INT prevCount = *pcGlyphs;
1689 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1690 if (nextIndex > GSUB_E_NOGLYPH)
1692 i = nextIndex;
1693 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1695 shaped = (nextIndex > GSUB_E_NOGLYPH);
1698 if (!shaped)
1700 if (context_shape[i] == Xn)
1702 WORD newGlyph = pwOutGlyphs[i];
1703 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1705 /* fall back to presentation form B */
1706 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1707 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1708 pwOutGlyphs[i] = newGlyph;
1711 i++;
1715 HeapFree(GetProcessHeap(),0,context_shape);
1716 HeapFree(GetProcessHeap(),0,context_type);
1720 * ContextualShape_Syriac
1723 #define ALAPH 0x710
1724 #define DALATH 0x715
1725 #define RISH 0x72A
1727 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1729 CHAR *context_type;
1730 INT *context_shape;
1731 INT dirR, dirL;
1732 int i;
1734 if (*pcGlyphs != cChars)
1736 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1737 return;
1740 if (!psa->fLogicalOrder && psa->fRTL)
1742 dirR = 1;
1743 dirL = -1;
1745 else
1747 dirR = -1;
1748 dirL = 1;
1751 if (!psc->GSUB_Table)
1752 psc->GSUB_Table = load_gsub_table(hdc);
1754 if (!psc->GSUB_Table)
1755 return;
1757 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1758 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1760 for (i = 0; i < cChars; i++)
1761 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1763 for (i = 0; i < cChars; i++)
1765 if (pwcChars[i] == ALAPH)
1767 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1769 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1770 context_shape[i] = Afj;
1771 else if ( rchar != DALATH && rchar != RISH &&
1772 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1773 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1774 context_shape[i] = Afn;
1775 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1776 context_shape[i] = Afx;
1777 else
1778 context_shape[i] = Xn;
1780 else if (context_type[i] == jtR &&
1781 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1782 context_shape[i] = Xr;
1783 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1784 context_shape[i] = Xl;
1785 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)))
1786 context_shape[i] = Xm;
1787 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1788 context_shape[i] = Xr;
1789 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1790 context_shape[i] = Xl;
1791 else
1792 context_shape[i] = Xn;
1795 /* Contextual Shaping */
1796 i = 0;
1797 while(i < *pcGlyphs)
1799 INT nextIndex;
1800 INT prevCount = *pcGlyphs;
1801 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1802 if (nextIndex > GSUB_E_NOGLYPH)
1804 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1805 i = nextIndex;
1807 else
1808 i++;
1811 HeapFree(GetProcessHeap(),0,context_shape);
1812 HeapFree(GetProcessHeap(),0,context_type);
1816 * ContextualShape_Phags_pa
1819 #define phags_pa_CANDRABINDU 0xA873
1820 #define phags_pa_START 0xA840
1821 #define phags_pa_END 0xA87F
1823 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1825 INT *context_shape;
1826 INT dirR, dirL;
1827 int i;
1829 if (*pcGlyphs != cChars)
1831 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1832 return;
1835 if (!psa->fLogicalOrder && psa->fRTL)
1837 dirR = 1;
1838 dirL = -1;
1840 else
1842 dirR = -1;
1843 dirL = 1;
1846 if (!psc->GSUB_Table)
1847 psc->GSUB_Table = load_gsub_table(hdc);
1849 if (!psc->GSUB_Table)
1850 return;
1852 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1854 for (i = 0; i < cChars; i++)
1856 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1858 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1859 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1860 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1861 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1863 if (jrchar && jlchar)
1864 context_shape[i] = Xm;
1865 else if (jrchar)
1866 context_shape[i] = Xr;
1867 else if (jlchar)
1868 context_shape[i] = Xl;
1869 else
1870 context_shape[i] = Xn;
1872 else
1873 context_shape[i] = -1;
1876 /* Contextual Shaping */
1877 i = 0;
1878 while(i < *pcGlyphs)
1880 if (context_shape[i] >= 0)
1882 INT nextIndex;
1883 INT prevCount = *pcGlyphs;
1884 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1885 if (nextIndex > GSUB_E_NOGLYPH)
1887 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1888 i = nextIndex;
1890 else
1891 i++;
1893 else
1894 i++;
1897 HeapFree(GetProcessHeap(),0,context_shape);
1900 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1902 int i;
1904 /* Replace */
1905 pwOutChars[cWalk] = replacements[0];
1906 cWalk=cWalk+1;
1908 /* Insert */
1909 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1911 int j;
1912 for (j = *pcChars; j > cWalk; j--)
1913 pwOutChars[j] = pwOutChars[j-1];
1914 *pcChars= *pcChars+1;
1915 pwOutChars[cWalk] = replacements[i];
1916 cWalk = cWalk+1;
1920 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1922 int i;
1923 int cWalk;
1925 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1927 for (i = 0; vowels[i].base != 0x0; i++)
1929 if (pwOutChars[cWalk] == vowels[i].base)
1931 int o = 0;
1932 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1933 if (vowels[i].parts[1]) { cWalk++; o++; }
1934 if (vowels[i].parts[2]) { cWalk++; o++; }
1935 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1936 break;
1942 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1944 int i;
1945 int offset = 0;
1946 int cWalk;
1948 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1950 for (i = 0; consonants[i].output!= 0x0; i++)
1952 int j;
1953 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1954 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1955 break;
1957 if (consonants[i].parts[j]==0x0) /* matched all */
1959 int k;
1960 j--;
1961 pwOutChars[cWalk] = consonants[i].output;
1962 for(k = cWalk+1; k < *pcChars - j; k++)
1963 pwOutChars[k] = pwOutChars[k+j];
1964 *pcChars = *pcChars - j;
1965 for (k = j ; k > 0; k--)
1966 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1967 offset += j;
1968 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1969 pwLogClust[k]--;
1970 break;
1973 cWalk++;
1977 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1979 if (s->ralf >= 0)
1981 int j;
1982 WORD Ra = pwChar[s->start];
1983 WORD H = pwChar[s->start+1];
1985 TRACE("Doing reorder of Ra to %i\n",s->base);
1986 for (j = s->start; j < s->base-1; j++)
1987 pwChar[j] = pwChar[j+2];
1988 pwChar[s->base-1] = Ra;
1989 pwChar[s->base] = H;
1991 s->ralf = s->base-1;
1992 s->base -= 2;
1996 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1998 if (s->ralf >= 0)
2000 int j,loc;
2001 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
2002 WORD Ra = pwChar[s->start];
2003 WORD H = pwChar[s->start+1];
2004 for (loc = s->end; loc > stop; loc--)
2005 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
2006 break;
2008 TRACE("Doing reorder of Ra to %i\n",loc);
2009 for (j = s->start; j < loc-1; j++)
2010 pwChar[j] = pwChar[j+2];
2011 pwChar[loc-1] = Ra;
2012 pwChar[loc] = H;
2014 s->ralf = loc-1;
2015 s->base -= 2;
2016 if (s->blwf >= 0) s->blwf -= 2;
2017 if (s->pref >= 0) s->pref -= 2;
2021 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2023 if (s->ralf >= 0)
2025 int j;
2026 WORD Ra = pwChar[s->start];
2027 WORD H = pwChar[s->start+1];
2029 TRACE("Doing reorder of Ra to %i\n",s->end-1);
2030 for (j = s->start; j < s->end-1; j++)
2031 pwChar[j] = pwChar[j+2];
2032 pwChar[s->end-1] = Ra;
2033 pwChar[s->end] = H;
2035 s->ralf = s->end-1;
2036 s->base -= 2;
2037 if (s->blwf >= 0) s->blwf -= 2;
2038 if (s->pref >= 0) s->pref -= 2;
2042 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2044 int i;
2046 /* reorder Matras */
2047 if (s->end > s->base)
2049 for (i = 1; i <= s->end-s->base; i++)
2051 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2053 int j;
2054 WCHAR c = pwChar[s->base+i];
2055 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
2056 for (j = s->base+i; j > s->base; j--)
2057 pwChar[j] = pwChar[j-1];
2058 pwChar[s->base] = c;
2060 if (s->ralf >= s->base) s->ralf++;
2061 if (s->blwf >= s->base) s->blwf++;
2062 if (s->pref >= s->base) s->pref++;
2063 s->base ++;
2069 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2071 int i;
2073 /* reorder Matras */
2074 if (s->end > s->base)
2076 for (i = 1; i <= s->end-s->base; i++)
2078 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2080 int j;
2081 WCHAR c = pwChar[s->base+i];
2082 TRACE("Doing reorder of %x to %i\n",c,s->start);
2083 for (j = s->base+i; j > s->start; j--)
2084 pwChar[j] = pwChar[j-1];
2085 pwChar[s->start] = c;
2087 if (s->ralf >= 0) s->ralf++;
2088 if (s->blwf >= 0) s->blwf++;
2089 if (s->pref >= 0) s->pref++;
2090 s->base ++;
2096 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2098 if (s->blwf >= 0 && g->blwf > g->base)
2100 int j,loc;
2101 int g_offset;
2102 for (loc = s->end; loc > s->blwf; loc--)
2103 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2104 break;
2106 g_offset = (loc - s->blwf) - 1;
2108 if (loc != s->blwf)
2110 WORD blwf = glyphs[g->blwf];
2111 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2112 /* do not care about the pwChar array anymore, just the glyphs */
2113 for (j = 0; j < g_offset; j++)
2114 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2115 glyphs[g->blwf + g_offset] = blwf;
2120 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2122 int i;
2124 /* reorder previously moved Matras to correct position*/
2125 for (i = s->start; i < s->base; i++)
2127 if (lexical(pwChar[i]) == lex_Matra_pre)
2129 int j;
2130 int g_start = g->start + i - s->start;
2131 if (g_start < g->base -1 )
2133 WCHAR og = glyphs[g_start];
2134 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2135 for (j = g_start; j < g->base-1; j++)
2136 glyphs[j] = glyphs[j+1];
2137 glyphs[g->base-1] = og;
2143 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2145 if (s->pref >= 0 && g->pref > g->base)
2147 int j;
2148 WCHAR og = glyphs[g->pref];
2149 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2150 for (j = g->pref; j > g->base; j--)
2151 glyphs[j] = glyphs[j-1];
2152 glyphs[g->base] = og;
2156 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2158 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2159 if (s->start == s->base && s->base == s->end) return;
2160 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2162 Reorder_Ra_follows_base(pwChar, s, lexical);
2163 Reorder_Matra_precede_base(pwChar, s, lexical);
2166 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2168 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2169 if (s->start == s->base && s->base == s->end) return;
2170 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2172 Reorder_Ra_follows_matra(pwChar, s, lexical);
2173 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2176 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2178 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2179 if (s->start == s->base && s->base == s->end) return;
2180 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2182 Reorder_Ra_follows_base(pwChar, s, lexical);
2183 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2186 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2188 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2189 if (s->start == s->base && s->base == s->end) return;
2190 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2192 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2193 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2196 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2198 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2199 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2200 if (s->start == s->base && s->base == s->end) return;
2201 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2203 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2206 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2208 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2209 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2210 if (s->start == s->base && s->base == s->end) return;
2211 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2213 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2214 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2218 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2220 if (shift == 0)
2221 return;
2223 if (glyph_index->start > index)
2224 glyph_index->start += shift;
2225 if (glyph_index->base > index)
2226 glyph_index->base+= shift;
2227 if (glyph_index->end > index)
2228 glyph_index->end+= shift;
2229 if (glyph_index->ralf > index)
2230 glyph_index->ralf+= shift;
2231 if (glyph_index->blwf > index)
2232 glyph_index->blwf+= shift;
2233 if (glyph_index->pref > index)
2234 glyph_index->pref+= shift;
2237 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 )
2239 int index = glyph_index->start;
2241 if (!feature)
2242 return;
2244 while(index <= glyph_index->end)
2246 INT nextIndex;
2247 INT prevCount = *pcGlyphs;
2248 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2249 if (nextIndex > GSUB_E_NOGLYPH)
2251 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2252 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2253 index = nextIndex;
2255 else
2256 index++;
2260 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2262 int i = 0;
2263 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)))))
2264 i++;
2265 if (index + i <= end-1)
2266 return index + i;
2267 else
2268 return -1;
2271 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)
2273 INT index, nextIndex;
2274 INT count,g_offset;
2276 count = syllable->base - syllable->start;
2278 g_offset = 0;
2279 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2280 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2282 INT prevCount = *pcGlyphs;
2283 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2284 if (nextIndex > GSUB_E_NOGLYPH)
2286 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2287 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2288 g_offset += (*pcGlyphs - prevCount);
2291 index+=2;
2292 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2296 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)
2298 INT nextIndex;
2299 INT prevCount = *pcGlyphs;
2301 if (syllable->ralf >= 0)
2303 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2304 if (nextIndex > GSUB_E_NOGLYPH)
2306 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2307 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2312 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2314 int i = 0;
2315 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2316 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2317 is_consonant(lexical(pwChars[index+i+1])))))
2318 i++;
2319 if (index + i <= end-1)
2320 return index+i;
2321 else
2322 return -1;
2325 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)
2327 INT index, nextIndex;
2328 INT count, g_offset=0;
2329 INT ralf = syllable->ralf;
2331 count = syllable->end - syllable->base;
2333 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2335 while (index >= 0)
2337 INT prevCount = *pcGlyphs;
2338 if (ralf >=0 && ralf < index)
2340 g_offset--;
2341 ralf = -1;
2344 if (!modern)
2346 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2347 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2348 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2351 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2352 if (nextIndex > GSUB_E_NOGLYPH)
2354 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2355 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2356 g_offset += (*pcGlyphs - prevCount);
2358 else if (!modern)
2360 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2361 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2362 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2365 index+=2;
2366 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2370 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)
2372 int c;
2373 int overall_shift = 0;
2374 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2375 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2376 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2377 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2378 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2379 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2380 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2381 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2382 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2383 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2384 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2385 IndicSyllable glyph_indexs;
2387 for (c = 0; c < syllable_count; c++)
2389 int old_end;
2390 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2391 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2392 old_end = glyph_indexs.end;
2394 if (locl)
2396 TRACE("applying feature locl\n");
2397 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2399 if (nukt)
2401 TRACE("applying feature nukt\n");
2402 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2404 if (akhn)
2406 TRACE("applying feature akhn\n");
2407 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2410 if (rphf)
2411 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2412 if (rkrf)
2414 TRACE("applying feature rkrf\n");
2415 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2417 if (pref)
2418 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2419 if (blwf)
2421 if (!modern)
2422 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2424 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2427 if (half)
2428 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2429 if (pstf)
2431 TRACE("applying feature pstf\n");
2432 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2434 if (vatu)
2436 TRACE("applying feature vatu\n");
2437 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2439 if (cjct)
2441 TRACE("applying feature cjct\n");
2442 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2445 if (second_reorder)
2446 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2448 overall_shift += glyph_indexs.end - old_end;
2452 static inline int unicode_lex(WCHAR c)
2454 int type;
2456 if (!c) return lex_Generic;
2457 if (c == 0x200D) return lex_ZWJ;
2458 if (c == 0x200C) return lex_ZWNJ;
2459 if (c == 0x00A0) return lex_NBSP;
2461 type = get_table_entry( indic_syllabic_table, c );
2463 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2465 switch( type )
2467 case 0x0d07: /* Unknown */
2468 case 0x0e07: /* Unknwon */
2469 default: return lex_Generic;
2470 case 0x0001:
2471 case 0x0002:
2472 case 0x0011:
2473 case 0x0012:
2474 case 0x0013:
2475 case 0x0014: return lex_Modifier;
2476 case 0x0003:
2477 case 0x0009:
2478 case 0x000a:
2479 case 0x000b:
2480 case 0x000d:
2481 case 0x000e:
2482 case 0x000f:
2483 case 0x0010: return lex_Consonant;
2484 case 0x0004: return lex_Nukta;
2485 case 0x0005: return lex_Halant;
2486 case 0x0006:
2487 case 0x0008: return lex_Vowel;
2488 case 0x0007:
2489 case 0x0107: return lex_Matra_post;
2490 case 0x0207:
2491 case 0x0307: return lex_Matra_pre;
2492 case 0x0807:
2493 case 0x0907:
2494 case 0x0a07:
2495 case 0x0b07:
2496 case 0x0c07:
2497 case 0x0407: return lex_Composed_Vowel;
2498 case 0x0507: return lex_Matra_above;
2499 case 0x0607: return lex_Matra_below;
2500 case 0x000c: return lex_Ra;
2504 static int sinhala_lex(WCHAR c)
2506 switch (c)
2508 case 0x0DDA:
2509 case 0x0DDD:
2510 case 0x0DDC:
2511 case 0x0DDE: return lex_Matra_post;
2512 default:
2513 return unicode_lex(c);
2517 static const VowelComponents Sinhala_vowels[] = {
2518 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2519 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2520 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2521 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2522 {0x0000, {0x0000,0x0000,0x0}}};
2524 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2526 int cCount = cChars;
2527 int i;
2528 WCHAR *input;
2529 IndicSyllable *syllables = NULL;
2530 int syllable_count = 0;
2532 if (*pcGlyphs != cChars)
2534 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2535 return;
2538 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2540 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2542 /* Step 1: Decompose multi part vowels */
2543 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2545 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2547 /* Step 2: Reorder within Syllables */
2548 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2549 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2551 /* Step 3: Strip dangling joiners */
2552 for (i = 0; i < cCount; i++)
2554 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2555 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2556 input[i] = 0x0020;
2559 /* Step 4: Base Form application to syllables */
2560 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2561 *pcGlyphs = cCount;
2562 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2564 HeapFree(GetProcessHeap(),0,input);
2565 HeapFree(GetProcessHeap(),0,syllables);
2568 static int devanagari_lex(WCHAR c)
2570 switch (c)
2572 case 0x0930: return lex_Ra;
2573 default:
2574 return unicode_lex(c);
2578 static const ConsonantComponents Devanagari_consonants[] ={
2579 {{0x0928, 0x093C, 0x00000}, 0x0929},
2580 {{0x0930, 0x093C, 0x00000}, 0x0931},
2581 {{0x0933, 0x093C, 0x00000}, 0x0934},
2582 {{0x0915, 0x093C, 0x00000}, 0x0958},
2583 {{0x0916, 0x093C, 0x00000}, 0x0959},
2584 {{0x0917, 0x093C, 0x00000}, 0x095A},
2585 {{0x091C, 0x093C, 0x00000}, 0x095B},
2586 {{0x0921, 0x093C, 0x00000}, 0x095C},
2587 {{0x0922, 0x093C, 0x00000}, 0x095D},
2588 {{0x092B, 0x093C, 0x00000}, 0x095E},
2589 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2591 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2593 int cCount = cChars;
2594 WCHAR *input;
2595 IndicSyllable *syllables = NULL;
2596 int syllable_count = 0;
2597 BOOL modern = get_GSUB_Indic2(psa, psc);
2599 if (*pcGlyphs != cChars)
2601 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2602 return;
2605 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2606 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2608 /* Step 1: Compose Consonant and Nukta */
2609 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2610 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2612 /* Step 2: Reorder within Syllables */
2613 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2614 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2615 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2616 *pcGlyphs = cCount;
2618 /* Step 3: Base Form application to syllables */
2619 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2621 HeapFree(GetProcessHeap(),0,input);
2622 HeapFree(GetProcessHeap(),0,syllables);
2625 static int bengali_lex(WCHAR c)
2627 switch (c)
2629 case 0x09B0: return lex_Ra;
2630 default:
2631 return unicode_lex(c);
2635 static const VowelComponents Bengali_vowels[] = {
2636 {0x09CB, {0x09C7,0x09BE,0x0000}},
2637 {0x09CC, {0x09C7,0x09D7,0x0000}},
2638 {0x0000, {0x0000,0x0000,0x0000}}};
2640 static const ConsonantComponents Bengali_consonants[] = {
2641 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2642 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2643 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2644 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2645 {{0x0000,0x0000,0x0000}, 0x0000}};
2647 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2649 int cCount = cChars;
2650 WCHAR *input;
2651 IndicSyllable *syllables = NULL;
2652 int syllable_count = 0;
2653 BOOL modern = get_GSUB_Indic2(psa, psc);
2655 if (*pcGlyphs != cChars)
2657 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2658 return;
2661 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2662 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2664 /* Step 1: Decompose Vowels and Compose Consonents */
2665 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2666 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2667 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2669 /* Step 2: Reorder within Syllables */
2670 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2671 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2672 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2673 *pcGlyphs = cCount;
2675 /* Step 3: Initial form is only applied to the beginning of words */
2676 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2678 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2680 int index = cCount;
2681 int gCount = 1;
2682 if (index > 0) index++;
2684 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2688 /* Step 4: Base Form application to syllables */
2689 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2691 HeapFree(GetProcessHeap(),0,input);
2692 HeapFree(GetProcessHeap(),0,syllables);
2695 static int gurmukhi_lex(WCHAR c)
2697 if (c == 0x0A71)
2698 return lex_Modifier;
2699 else
2700 return unicode_lex(c);
2703 static const ConsonantComponents Gurmukhi_consonants[] = {
2704 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2705 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2706 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2707 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2708 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2709 {{0x0000,0x0000,0x0000}, 0x0000}};
2711 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2713 int cCount = cChars;
2714 WCHAR *input;
2715 IndicSyllable *syllables = NULL;
2716 int syllable_count = 0;
2717 BOOL modern = get_GSUB_Indic2(psa, psc);
2719 if (*pcGlyphs != cChars)
2721 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2722 return;
2725 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2726 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2728 /* Step 1: Compose Consonents */
2729 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2730 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2732 /* Step 2: Reorder within Syllables */
2733 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2734 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2735 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2736 *pcGlyphs = cCount;
2738 /* Step 3: Base Form application to syllables */
2739 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2741 HeapFree(GetProcessHeap(),0,input);
2742 HeapFree(GetProcessHeap(),0,syllables);
2745 static int gujarati_lex(WCHAR c)
2747 switch (c)
2749 case 0x0AB0: return lex_Ra;
2750 default:
2751 return unicode_lex(c);
2755 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2757 int cCount = cChars;
2758 WCHAR *input;
2759 IndicSyllable *syllables = NULL;
2760 int syllable_count = 0;
2761 BOOL modern = get_GSUB_Indic2(psa, psc);
2763 if (*pcGlyphs != cChars)
2765 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2766 return;
2769 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2770 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2772 /* Step 1: Reorder within Syllables */
2773 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2774 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2775 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2776 *pcGlyphs = cCount;
2778 /* Step 2: Base Form application to syllables */
2779 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2781 HeapFree(GetProcessHeap(),0,input);
2782 HeapFree(GetProcessHeap(),0,syllables);
2785 static int oriya_lex(WCHAR c)
2787 switch (c)
2789 case 0x0B30: return lex_Ra;
2790 default:
2791 return unicode_lex(c);
2795 static const VowelComponents Oriya_vowels[] = {
2796 {0x0B48, {0x0B47,0x0B56,0x0000}},
2797 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2798 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2799 {0x0000, {0x0000,0x0000,0x0000}}};
2801 static const ConsonantComponents Oriya_consonants[] = {
2802 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2803 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2804 {{0x0000,0x0000,0x0000}, 0x0000}};
2806 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2808 int cCount = cChars;
2809 WCHAR *input;
2810 IndicSyllable *syllables = NULL;
2811 int syllable_count = 0;
2812 BOOL modern = get_GSUB_Indic2(psa, psc);
2814 if (*pcGlyphs != cChars)
2816 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2817 return;
2820 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2821 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2823 /* Step 1: Decompose Vowels and Compose Consonents */
2824 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2825 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2826 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2828 /* Step 2: Reorder within Syllables */
2829 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2830 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2831 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2832 *pcGlyphs = cCount;
2834 /* Step 3: Base Form application to syllables */
2835 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2837 HeapFree(GetProcessHeap(),0,input);
2838 HeapFree(GetProcessHeap(),0,syllables);
2841 static int tamil_lex(WCHAR c)
2843 return unicode_lex(c);
2846 static const VowelComponents Tamil_vowels[] = {
2847 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2848 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2849 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2850 {0x0000, {0x0000,0x0000,0x0000}}};
2852 static const ConsonantComponents Tamil_consonants[] = {
2853 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2854 {{0x0000,0x0000,0x0000}, 0x0000}};
2856 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2858 int cCount = cChars;
2859 WCHAR *input;
2860 IndicSyllable *syllables = NULL;
2861 int syllable_count = 0;
2862 BOOL modern = get_GSUB_Indic2(psa, psc);
2864 if (*pcGlyphs != cChars)
2866 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2867 return;
2870 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2871 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2873 /* Step 1: Decompose Vowels and Compose Consonents */
2874 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2875 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2876 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2878 /* Step 2: Reorder within Syllables */
2879 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2880 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2881 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2882 *pcGlyphs = cCount;
2884 /* Step 3: Base Form application to syllables */
2885 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2887 HeapFree(GetProcessHeap(),0,input);
2888 HeapFree(GetProcessHeap(),0,syllables);
2891 static int telugu_lex(WCHAR c)
2893 switch (c)
2895 case 0x0C43:
2896 case 0x0C44: return lex_Modifier;
2897 default:
2898 return unicode_lex(c);
2902 static const VowelComponents Telugu_vowels[] = {
2903 {0x0C48, {0x0C46,0x0C56,0x0000}},
2904 {0x0000, {0x0000,0x0000,0x0000}}};
2906 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2908 int cCount = cChars;
2909 WCHAR *input;
2910 IndicSyllable *syllables = NULL;
2911 int syllable_count = 0;
2912 BOOL modern = get_GSUB_Indic2(psa, psc);
2914 if (*pcGlyphs != cChars)
2916 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2917 return;
2920 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2921 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2923 /* Step 1: Decompose Vowels */
2924 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2925 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2927 /* Step 2: Reorder within Syllables */
2928 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2929 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2930 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2931 *pcGlyphs = cCount;
2933 /* Step 3: Base Form application to syllables */
2934 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2936 HeapFree(GetProcessHeap(),0,input);
2937 HeapFree(GetProcessHeap(),0,syllables);
2940 static int kannada_lex(WCHAR c)
2942 switch (c)
2944 case 0x0CB0: return lex_Ra;
2945 default:
2946 return unicode_lex(c);
2950 static const VowelComponents Kannada_vowels[] = {
2951 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2952 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2953 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2954 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2955 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2956 {0x0000, {0x0000,0x0000,0x0000}}};
2958 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2960 int cCount = cChars;
2961 WCHAR *input;
2962 IndicSyllable *syllables = NULL;
2963 int syllable_count = 0;
2964 BOOL modern = get_GSUB_Indic2(psa, psc);
2966 if (*pcGlyphs != cChars)
2968 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2969 return;
2972 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2973 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2975 /* Step 1: Decompose Vowels */
2976 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2977 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2979 /* Step 2: Reorder within Syllables */
2980 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2981 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2982 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2983 *pcGlyphs = cCount;
2985 /* Step 3: Base Form application to syllables */
2986 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2988 HeapFree(GetProcessHeap(),0,input);
2989 HeapFree(GetProcessHeap(),0,syllables);
2992 static int malayalam_lex(WCHAR c)
2994 return unicode_lex(c);
2997 static const VowelComponents Malayalam_vowels[] = {
2998 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2999 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
3000 {0x0D4C, {0x0D46,0x0D57,0x0000}},
3001 {0x0000, {0x0000,0x0000,0x0000}}};
3003 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3005 int cCount = cChars;
3006 WCHAR *input;
3007 IndicSyllable *syllables = NULL;
3008 int syllable_count = 0;
3009 BOOL modern = get_GSUB_Indic2(psa, psc);
3011 if (*pcGlyphs != cChars)
3013 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3014 return;
3017 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
3018 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3020 /* Step 1: Decompose Vowels */
3021 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
3022 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
3024 /* Step 2: Reorder within Syllables */
3025 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
3026 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3027 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3028 *pcGlyphs = cCount;
3030 /* Step 3: Base Form application to syllables */
3031 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
3033 HeapFree(GetProcessHeap(),0,input);
3034 HeapFree(GetProcessHeap(),0,syllables);
3037 static int khmer_lex(WCHAR c)
3039 return unicode_lex(c);
3042 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3044 int cCount = cChars;
3045 WCHAR *input;
3046 IndicSyllable *syllables = NULL;
3047 int syllable_count = 0;
3049 if (*pcGlyphs != cChars)
3051 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3052 return;
3055 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
3056 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3058 /* Step 1: Reorder within Syllables */
3059 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
3060 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3061 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3062 *pcGlyphs = cCount;
3064 /* Step 2: Base Form application to syllables */
3065 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
3067 HeapFree(GetProcessHeap(),0,input);
3068 HeapFree(GetProcessHeap(),0,syllables);
3071 static inline BOOL mongolian_wordbreak(WCHAR chr)
3073 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
3076 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3078 INT *context_shape;
3079 INT dirL;
3080 int i;
3082 if (*pcGlyphs != cChars)
3084 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3085 return;
3088 if (!psa->fLogicalOrder && psa->fRTL)
3089 dirL = -1;
3090 else
3091 dirL = 1;
3093 if (!psc->GSUB_Table)
3094 psc->GSUB_Table = load_gsub_table(hdc);
3096 if (!psc->GSUB_Table)
3097 return;
3099 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
3101 for (i = 0; i < cChars; i++)
3103 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
3105 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
3106 context_shape[i] = Xn;
3107 else
3108 context_shape[i] = Xl;
3110 else
3112 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
3113 context_shape[i] = Xr;
3114 else
3115 context_shape[i] = Xm;
3119 /* Contextual Shaping */
3120 i = 0;
3121 while(i < *pcGlyphs)
3123 INT nextIndex;
3124 INT prevCount = *pcGlyphs;
3125 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
3126 if (nextIndex > GSUB_E_NOGLYPH)
3128 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
3129 i = nextIndex;
3131 else
3132 i++;
3135 HeapFree(GetProcessHeap(),0,context_shape);
3138 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)
3140 int i,k;
3142 for (i = 0; i < cGlyphs; i++)
3144 int char_index[20];
3145 int char_count = 0;
3147 for (k = 0; k < cChars; k++)
3149 if (pwLogClust[k] == i)
3151 char_index[char_count] = k;
3152 char_count++;
3156 if (char_count == 0)
3157 continue;
3159 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3161 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3162 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3164 else
3165 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3168 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3169 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3172 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 )
3174 int i,k;
3175 int initGlyph, finaGlyph;
3176 INT dirR, dirL;
3177 BYTE *spaces;
3179 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3180 memset(spaces,0,cGlyphs);
3182 if (!psa->fLogicalOrder && psa->fRTL)
3184 initGlyph = cGlyphs-1;
3185 finaGlyph = 0;
3186 dirR = 1;
3187 dirL = -1;
3189 else
3191 initGlyph = 0;
3192 finaGlyph = cGlyphs-1;
3193 dirR = -1;
3194 dirL = 1;
3197 for (i = 0; i < cGlyphs; i++)
3199 for (k = 0; k < cChars; k++)
3200 if (pwLogClust[k] == i)
3202 if (pwcChars[k] == 0x0020)
3203 spaces[i] = 1;
3207 for (i = 0; i < cGlyphs; i++)
3209 int char_index[20];
3210 int char_count = 0;
3211 BOOL isInit, isFinal;
3213 for (k = 0; k < cChars; k++)
3215 if (pwLogClust[k] == i)
3217 char_index[char_count] = k;
3218 char_count++;
3222 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3223 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3225 if (char_count == 0)
3226 continue;
3228 if (char_count == 1)
3230 if (pwcChars[char_index[0]] == 0x0020) /* space */
3232 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3233 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3235 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3236 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3237 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3239 if (!isInit && !isFinal)
3240 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3241 else if (isInit)
3242 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3243 else
3244 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3246 else if (!isInit)
3248 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3249 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3250 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3251 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3252 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3253 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3254 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3255 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3256 else
3257 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3259 else if (!isInit && !isFinal)
3260 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3261 else
3262 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3264 else if (char_count == 2)
3266 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3267 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3268 else if (!isInit)
3269 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3270 else
3271 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3273 else if (!isInit && !isFinal)
3274 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3275 else
3276 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3279 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3280 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3281 HeapFree(GetProcessHeap(),0,spaces);
3284 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 )
3286 int i,k;
3287 int finaGlyph;
3288 INT dirL;
3289 BYTE *spaces;
3291 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3292 memset(spaces,0,cGlyphs);
3294 if (!psa->fLogicalOrder && psa->fRTL)
3296 finaGlyph = 0;
3297 dirL = -1;
3299 else
3301 finaGlyph = cGlyphs-1;
3302 dirL = 1;
3305 for (i = 0; i < cGlyphs; i++)
3307 for (k = 0; k < cChars; k++)
3308 if (pwLogClust[k] == i)
3310 if (pwcChars[k] == 0x0020)
3311 spaces[i] = 1;
3315 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3317 for (i = 0; i < cGlyphs; i++)
3319 int char_index[20];
3320 int char_count = 0;
3322 for (k = 0; k < cChars; k++)
3324 if (pwLogClust[k] == i)
3326 char_index[char_count] = k;
3327 char_count++;
3331 if (char_count == 0)
3332 continue;
3334 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3336 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3337 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3339 else if (i == finaGlyph)
3340 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3341 else
3342 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3344 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3345 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3346 pGlyphProp[i].sva.fClusterStart = 0;
3349 HeapFree(GetProcessHeap(),0,spaces);
3350 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3352 /* Do not allow justification between marks and their base */
3353 for (i = 0; i < cGlyphs; i++)
3355 if (!pGlyphProp[i].sva.fClusterStart)
3356 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3360 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)
3362 int i,k;
3364 for (i = 0; i < cGlyphs; i++)
3366 int char_index[20];
3367 int char_count = 0;
3369 for (k = 0; k < cChars; k++)
3371 if (pwLogClust[k] == i)
3373 char_index[char_count] = k;
3374 char_count++;
3378 if (char_count == 0)
3379 continue;
3381 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3383 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3384 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3386 else
3387 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3389 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3390 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3393 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)
3395 int i,k;
3397 for (i = 0; i < cGlyphs; i++)
3399 int char_index[20];
3400 int char_count = 0;
3402 for (k = 0; k < cChars; k++)
3404 if (pwLogClust[k] == i)
3406 char_index[char_count] = k;
3407 char_count++;
3411 if (char_count == 0)
3412 continue;
3414 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3416 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3417 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3419 else
3420 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3422 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3423 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3425 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3426 for (i = 0; i < cGlyphs; i++)
3428 if (!pGlyphProp[i].sva.fClusterStart)
3430 pGlyphProp[i].sva.fDiacritic = 0;
3431 pGlyphProp[i].sva.fZeroWidth = 0;
3436 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)
3438 int i,k;
3440 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3441 for (i = 0; i < cGlyphs; i++)
3443 int char_index[20];
3444 int char_count = 0;
3446 for (k = 0; k < cChars; k++)
3448 if (pwLogClust[k] == i)
3450 char_index[char_count] = k;
3451 char_count++;
3455 if (override_gsub)
3457 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3458 pGlyphProp[i].sva.fDiacritic = FALSE;
3459 pGlyphProp[i].sva.fZeroWidth = FALSE;
3462 if (char_count == 0)
3463 continue;
3465 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3467 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3468 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3470 else
3471 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3473 pGlyphProp[i].sva.fClusterStart = 0;
3474 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3475 switch (lexical(pwcChars[char_index[k]]))
3477 case lex_Matra_pre:
3478 case lex_Matra_post:
3479 case lex_Matra_above:
3480 case lex_Matra_below:
3481 case lex_Modifier:
3482 case lex_Halant:
3483 break;
3484 case lex_ZWJ:
3485 case lex_ZWNJ:
3486 /* check for dangling joiners */
3487 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3488 pGlyphProp[i].sva.fClusterStart = 1;
3489 else
3490 k = char_count;
3491 break;
3492 default:
3493 pGlyphProp[i].sva.fClusterStart = 1;
3494 break;
3498 if (use_syllables)
3500 IndicSyllable *syllables = NULL;
3501 int syllable_count = 0;
3502 BOOL modern = get_GSUB_Indic2(psa, psc);
3504 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3506 for (i = 0; i < syllable_count; i++)
3508 int j;
3509 WORD g = pwLogClust[syllables[i].start];
3510 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3512 if (pwLogClust[j] != g)
3514 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3515 pwLogClust[j] = g;
3520 HeapFree(GetProcessHeap(), 0, syllables);
3523 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3526 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 )
3528 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3531 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 )
3533 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3536 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 )
3538 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3541 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 )
3543 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3546 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 )
3548 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3551 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 )
3553 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3556 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 )
3558 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3561 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 )
3563 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3566 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 )
3568 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3571 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 )
3573 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3576 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 )
3578 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3581 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)
3583 if (ShapingData[psa->eScript].charGlyphPropProc)
3584 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3585 else
3586 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3589 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3591 if (!psc->GSUB_Table)
3592 psc->GSUB_Table = load_gsub_table(hdc);
3594 if (ShapingData[psa->eScript].contextProc)
3595 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3598 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)
3600 int i;
3601 INT dirL;
3603 if (!rpRangeProperties)
3604 return;
3606 if (!psc->GSUB_Table)
3607 psc->GSUB_Table = load_gsub_table(hdc);
3609 if (!psc->GSUB_Table)
3610 return;
3612 if (!psa->fLogicalOrder && psa->fRTL)
3613 dirL = -1;
3614 else
3615 dirL = 1;
3617 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3619 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3620 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3624 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3626 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3627 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3629 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3632 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3634 const GSUB_Feature *feature;
3635 int i;
3637 if (!ShapingData[psa->eScript].requiredFeatures)
3638 return S_OK;
3640 if (!psc->GSUB_Table)
3641 psc->GSUB_Table = load_gsub_table(hdc);
3643 /* we need to have at least one of the required features */
3644 i = 0;
3645 while (ShapingData[psa->eScript].requiredFeatures[i])
3647 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3648 if (feature)
3649 return S_OK;
3650 i++;
3653 return USP_E_SCRIPT_NOT_IN_FONT;