usp10: Correct issues with LTR logclust indexing after Multiple substitution.
[wine.git] / dlls / usp10 / shape.c
blob2189b92471ab6b7b422af0aa0c78f3adfb4fa14d
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "usp10.h"
29 #include "winternl.h"
31 #include "usp10_internal.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
37 #define FIRST_ARABIC_CHAR 0x0600
38 #define LAST_ARABIC_CHAR 0x06ff
40 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
41 WCHAR*, INT, WORD*, INT*, INT, WORD*);
43 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
59 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
60 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
61 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
62 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
63 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
64 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
65 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
66 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
67 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
68 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
69 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
73 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
75 extern const unsigned short indic_syllabic_table[];
76 extern const unsigned short wine_shaping_table[];
77 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
79 enum joining_types {
80 jtU,
81 jtT,
82 jtR,
83 jtL,
84 jtD,
85 jtC
88 enum joined_forms {
89 Xn=0,
90 Xr,
91 Xl,
92 Xm,
93 /* Syriac Alaph */
94 Afj,
95 Afn,
96 Afx
99 #ifdef WORDS_BIGENDIAN
100 #define GET_BE_WORD(x) (x)
101 #else
102 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
103 #endif
105 /* These are all structures needed for the GSUB table */
106 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
107 #define GSUB_E_NOFEATURE -2
108 #define GSUB_E_NOGLYPH -1
110 typedef struct {
111 DWORD version;
112 WORD ScriptList;
113 WORD FeatureList;
114 WORD LookupList;
115 } GSUB_Header;
117 typedef struct {
118 CHAR ScriptTag[4];
119 WORD Script;
120 } GSUB_ScriptRecord;
122 typedef struct {
123 WORD ScriptCount;
124 GSUB_ScriptRecord ScriptRecord[1];
125 } GSUB_ScriptList;
127 typedef struct {
128 CHAR LangSysTag[4];
129 WORD LangSys;
130 } GSUB_LangSysRecord;
132 typedef struct {
133 WORD DefaultLangSys;
134 WORD LangSysCount;
135 GSUB_LangSysRecord LangSysRecord[1];
136 } GSUB_Script;
138 typedef struct {
139 WORD LookupOrder; /* Reserved */
140 WORD ReqFeatureIndex;
141 WORD FeatureCount;
142 WORD FeatureIndex[1];
143 } GSUB_LangSys;
145 typedef struct {
146 CHAR FeatureTag[4];
147 WORD Feature;
148 } GSUB_FeatureRecord;
150 typedef struct {
151 WORD FeatureCount;
152 GSUB_FeatureRecord FeatureRecord[1];
153 } GSUB_FeatureList;
155 typedef struct {
156 WORD FeatureParams; /* Reserved */
157 WORD LookupCount;
158 WORD LookupListIndex[1];
159 } GSUB_Feature;
161 typedef struct {
162 WORD LookupCount;
163 WORD Lookup[1];
164 } GSUB_LookupList;
166 typedef struct {
167 WORD LookupType;
168 WORD LookupFlag;
169 WORD SubTableCount;
170 WORD SubTable[1];
171 } GSUB_LookupTable;
173 typedef struct {
174 WORD CoverageFormat;
175 WORD GlyphCount;
176 WORD GlyphArray[1];
177 } GSUB_CoverageFormat1;
179 typedef struct {
180 WORD Start;
181 WORD End;
182 WORD StartCoverageIndex;
183 } GSUB_RangeRecord;
185 typedef struct {
186 WORD CoverageFormat;
187 WORD RangeCount;
188 GSUB_RangeRecord RangeRecord[1];
189 } GSUB_CoverageFormat2;
191 typedef struct {
192 WORD SubstFormat; /* = 1 */
193 WORD Coverage;
194 WORD DeltaGlyphID;
195 } GSUB_SingleSubstFormat1;
197 typedef struct {
198 WORD SubstFormat; /* = 2 */
199 WORD Coverage;
200 WORD GlyphCount;
201 WORD Substitute[1];
202 }GSUB_SingleSubstFormat2;
204 typedef struct {
205 WORD SubstFormat; /* = 1 */
206 WORD Coverage;
207 WORD SequenceCount;
208 WORD Sequence[1];
209 }GSUB_MultipleSubstFormat1;
211 typedef struct {
212 WORD GlyphCount;
213 WORD Substitute[1];
214 }GSUB_Sequence;
216 typedef struct {
217 WORD SubstFormat; /* = 1 */
218 WORD Coverage;
219 WORD LigSetCount;
220 WORD LigatureSet[1];
221 }GSUB_LigatureSubstFormat1;
223 typedef struct {
224 WORD LigatureCount;
225 WORD Ligature[1];
226 }GSUB_LigatureSet;
228 typedef struct{
229 WORD LigGlyph;
230 WORD CompCount;
231 WORD Component[1];
232 }GSUB_Ligature;
234 typedef struct{
235 WORD SequenceIndex;
236 WORD LookupListIndex;
238 }GSUB_SubstLookupRecord;
240 typedef struct{
241 WORD SubstFormat; /* = 1 */
242 WORD Coverage;
243 WORD ChainSubRuleSetCount;
244 WORD ChainSubRuleSet[1];
245 }GSUB_ChainContextSubstFormat1;
247 typedef struct {
248 WORD SubstFormat; /* = 3 */
249 WORD BacktrackGlyphCount;
250 WORD Coverage[1];
251 }GSUB_ChainContextSubstFormat3_1;
253 typedef struct{
254 WORD InputGlyphCount;
255 WORD Coverage[1];
256 }GSUB_ChainContextSubstFormat3_2;
258 typedef struct{
259 WORD LookaheadGlyphCount;
260 WORD Coverage[1];
261 }GSUB_ChainContextSubstFormat3_3;
263 typedef struct{
264 WORD SubstCount;
265 GSUB_SubstLookupRecord SubstLookupRecord[1];
266 }GSUB_ChainContextSubstFormat3_4;
268 typedef struct {
269 WORD SubstFormat; /* = 1 */
270 WORD Coverage;
271 WORD AlternateSetCount;
272 WORD AlternateSet[1];
273 } GSUB_AlternateSubstFormat1;
275 typedef struct{
276 WORD GlyphCount;
277 WORD Alternate[1];
278 } GSUB_AlternateSet;
280 /* These are all structures needed for the GDEF table */
281 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
283 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
285 typedef struct {
286 DWORD Version;
287 WORD GlyphClassDef;
288 WORD AttachList;
289 WORD LigCaretList;
290 WORD MarkAttachClassDef;
291 } GDEF_Header;
293 typedef struct {
294 WORD ClassFormat;
295 WORD StartGlyph;
296 WORD GlyphCount;
297 WORD ClassValueArray[1];
298 } GDEF_ClassDefFormat1;
300 typedef struct {
301 WORD Start;
302 WORD End;
303 WORD Class;
304 } GDEF_ClassRangeRecord;
306 typedef struct {
307 WORD ClassFormat;
308 WORD ClassRangeCount;
309 GDEF_ClassRangeRecord ClassRangeRecord[1];
310 } GDEF_ClassDefFormat2;
312 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
314 typedef struct tagVowelComponents
316 WCHAR base;
317 WCHAR parts[3];
318 } VowelComponents;
320 typedef struct tagConsonantComponents
322 WCHAR parts[3];
323 WCHAR output;
324 } ConsonantComponents;
326 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
328 /* the orders of joined_forms and contextual_features need to line up */
329 static const char* contextual_features[] =
331 "isol",
332 "fina",
333 "init",
334 "medi",
335 /* Syriac Alaph */
336 "med2",
337 "fin2",
338 "fin3"
341 static OPENTYPE_FEATURE_RECORD standard_features[] =
343 { MS_MAKE_TAG('c','c','m','p'), 1},
344 { MS_MAKE_TAG('l','o','c','l'), 1},
347 static OPENTYPE_FEATURE_RECORD latin_features[] =
349 { MS_MAKE_TAG('l','i','g','a'), 1},
350 { MS_MAKE_TAG('c','l','i','g'), 1},
353 static OPENTYPE_FEATURE_RECORD arabic_features[] =
355 { MS_MAKE_TAG('r','l','i','g'), 1},
356 { MS_MAKE_TAG('c','a','l','t'), 1},
357 { MS_MAKE_TAG('l','i','g','a'), 1},
358 { MS_MAKE_TAG('d','l','i','g'), 1},
359 { MS_MAKE_TAG('c','s','w','h'), 1},
360 { MS_MAKE_TAG('m','s','e','t'), 1},
363 static const char* required_arabic_features[] =
365 "fina",
366 "init",
367 "medi",
368 "rlig",
369 NULL
372 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
374 { MS_MAKE_TAG('d','l','i','g'), 0},
377 static OPENTYPE_FEATURE_RECORD syriac_features[] =
379 { MS_MAKE_TAG('r','l','i','g'), 1},
380 { MS_MAKE_TAG('c','a','l','t'), 1},
381 { MS_MAKE_TAG('l','i','g','a'), 1},
382 { MS_MAKE_TAG('d','l','i','g'), 1},
385 static const char* required_syriac_features[] =
387 "fina",
388 "fin2",
389 "fin3",
390 "init",
391 "medi",
392 "med2",
393 "rlig",
394 NULL
397 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
399 /* Presentation forms */
400 { MS_MAKE_TAG('b','l','w','s'), 1},
401 { MS_MAKE_TAG('a','b','v','s'), 1},
402 { MS_MAKE_TAG('p','s','t','s'), 1},
405 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
407 { MS_MAKE_TAG('a','b','v','s'), 1},
408 { MS_MAKE_TAG('b','l','w','s'), 1},
411 static OPENTYPE_FEATURE_RECORD phags_features[] =
413 { MS_MAKE_TAG('a','b','v','s'), 1},
414 { MS_MAKE_TAG('b','l','w','s'), 1},
415 { MS_MAKE_TAG('c','a','l','t'), 1},
418 static OPENTYPE_FEATURE_RECORD thai_features[] =
420 { MS_MAKE_TAG('c','c','m','p'), 1},
423 static const char* required_lao_features[] =
425 "ccmp",
426 NULL
429 static const char* required_devanagari_features[] =
431 "nukt",
432 "akhn",
433 "rphf",
434 "blwf",
435 "half",
436 "vatu",
437 "pres",
438 "abvs",
439 "blws",
440 "psts",
441 "haln",
442 NULL
445 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
447 { MS_MAKE_TAG('p','r','e','s'), 1},
448 { MS_MAKE_TAG('a','b','v','s'), 1},
449 { MS_MAKE_TAG('b','l','w','s'), 1},
450 { MS_MAKE_TAG('p','s','t','s'), 1},
451 { MS_MAKE_TAG('h','a','l','n'), 1},
452 { MS_MAKE_TAG('c','a','l','t'), 1},
455 static const char* required_bengali_features[] =
457 "nukt",
458 "akhn",
459 "rphf",
460 "blwf",
461 "half",
462 "vatu",
463 "pstf",
464 "init",
465 "abvs",
466 "blws",
467 "psts",
468 "haln",
469 NULL
472 static const char* required_gurmukhi_features[] =
474 "nukt",
475 "akhn",
476 "rphf",
477 "blwf",
478 "half",
479 "pstf",
480 "vatu",
481 "cjct",
482 "pres",
483 "abvs",
484 "blws",
485 "psts",
486 "haln",
487 "calt",
488 NULL
491 static const char* required_oriya_features[] =
493 "nukt",
494 "akhn",
495 "rphf",
496 "blwf",
497 "pstf",
498 "cjct",
499 "pres",
500 "abvs",
501 "blws",
502 "psts",
503 "haln",
504 "calt",
505 NULL
508 static const char* required_tamil_features[] =
510 "nukt",
511 "akhn",
512 "rphf",
513 "pref",
514 "half",
515 "pres",
516 "abvs",
517 "blws",
518 "psts",
519 "haln",
520 "calt",
521 NULL
524 static const char* required_telugu_features[] =
526 "nukt",
527 "akhn",
528 "rphf",
529 "pref",
530 "half",
531 "pstf",
532 "cjct",
533 "pres",
534 "abvs",
535 "blws",
536 "psts",
537 "haln",
538 "calt",
539 NULL
542 typedef struct ScriptShapeDataTag {
543 TEXTRANGE_PROPERTIES defaultTextRange;
544 const char** requiredFeatures;
545 CHAR otTag[5];
546 CHAR newOtTag[5];
547 ContextualShapingProc contextProc;
548 ShapeCharGlyphPropProc charGlyphPropProc;
549 } ScriptShapeData;
551 /* in order of scripts */
552 static const ScriptShapeData ShapingData[] =
554 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
555 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
556 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
557 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
558 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
559 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
560 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
561 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
562 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
563 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
564 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
565 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
566 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
567 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
568 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
569 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
570 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
571 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
572 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
573 {{ phags_features, 3}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
574 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
575 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
576 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
577 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
578 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
579 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
580 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
581 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
582 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
583 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
584 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
585 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
586 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
587 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
588 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
589 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
590 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
591 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
592 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
593 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
594 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
595 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
596 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
597 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
598 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
599 {{ latin_features, 2}, NULL, "latn" , "", NULL, NULL},
600 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
603 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
605 const GSUB_CoverageFormat1* cf1;
607 cf1 = table;
609 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
611 int count = GET_BE_WORD(cf1->GlyphCount);
612 int i;
613 TRACE("Coverage Format 1, %i glyphs\n",count);
614 for (i = 0; i < count; i++)
615 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
616 return i;
617 return -1;
619 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
621 const GSUB_CoverageFormat2* cf2;
622 int i;
623 int count;
624 cf2 = (const GSUB_CoverageFormat2*)cf1;
626 count = GET_BE_WORD(cf2->RangeCount);
627 TRACE("Coverage Format 2, %i ranges\n",count);
628 for (i = 0; i < count; i++)
630 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
631 return -1;
632 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
633 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
635 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
636 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
639 return -1;
641 else
642 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
644 return -1;
647 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
649 const GSUB_ScriptList *script;
650 const GSUB_Script *deflt = NULL;
651 int i;
652 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
654 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
655 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
657 const GSUB_Script *scr;
658 int offset;
660 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
661 scr = (const GSUB_Script*)((const BYTE*)script + offset);
663 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
664 return scr;
665 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
666 deflt = scr;
668 return deflt;
671 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
673 int i;
674 int offset;
675 const GSUB_LangSys *Lang;
677 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
679 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
681 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
682 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
684 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
685 return Lang;
687 offset = GET_BE_WORD(script->DefaultLangSys);
688 if (offset)
690 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
691 return Lang;
693 return NULL;
696 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
698 int i;
699 const GSUB_FeatureList *feature;
700 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
702 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
703 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
705 int index = GET_BE_WORD(lang->FeatureIndex[i]);
706 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
708 const GSUB_Feature *feat;
709 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
710 return feat;
713 return NULL;
716 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
718 int j;
719 TRACE("Single Substitution Subtable\n");
721 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
723 int offset;
724 const GSUB_SingleSubstFormat1 *ssf1;
725 offset = GET_BE_WORD(look->SubTable[j]);
726 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
727 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
729 int offset = GET_BE_WORD(ssf1->Coverage);
730 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
731 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
733 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
734 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
735 TRACE(" 0x%x\n",glyphs[glyph_index]);
736 return glyph_index + write_dir;
739 else
741 const GSUB_SingleSubstFormat2 *ssf2;
742 INT index;
743 INT offset;
745 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
746 offset = GET_BE_WORD(ssf1->Coverage);
747 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
748 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
749 TRACE(" Coverage index %i\n",index);
750 if (index != -1)
752 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
753 return GSUB_E_NOGLYPH;
755 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
756 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
757 TRACE("0x%x\n",glyphs[glyph_index]);
758 return glyph_index + write_dir;
762 return GSUB_E_NOGLYPH;
765 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
767 int j;
768 TRACE("Multiple Substitution Subtable\n");
770 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
772 int offset, index;
773 const GSUB_MultipleSubstFormat1 *msf1;
774 offset = GET_BE_WORD(look->SubTable[j]);
775 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
777 offset = GET_BE_WORD(msf1->Coverage);
778 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
779 if (index != -1)
781 const GSUB_Sequence *seq;
782 int sub_count;
783 int j;
784 offset = GET_BE_WORD(msf1->Sequence[index]);
785 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
786 sub_count = GET_BE_WORD(seq->GlyphCount);
787 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
789 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
790 glyphs[j] =glyphs[j-(sub_count-1)];
792 for (j = 0; j < sub_count; j++)
793 if (write_dir < 0)
794 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
795 else
796 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
798 *glyph_count = *glyph_count + (sub_count - 1);
800 if (TRACE_ON(uniscribe))
802 for (j = 0; j < sub_count; j++)
803 TRACE(" 0x%x",glyphs[glyph_index+j]);
804 TRACE("\n");
807 return glyph_index + (sub_count * write_dir);
810 return GSUB_E_NOGLYPH;
813 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
815 int j;
816 TRACE("Alternate Substitution Subtable\n");
818 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
820 int offset;
821 const GSUB_AlternateSubstFormat1 *asf1;
822 INT index;
824 offset = GET_BE_WORD(look->SubTable[j]);
825 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
826 offset = GET_BE_WORD(asf1->Coverage);
828 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
829 if (index != -1)
831 const GSUB_AlternateSet *as;
832 offset = GET_BE_WORD(asf1->AlternateSet[index]);
833 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
834 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
835 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
836 return GSUB_E_NOGLYPH;
838 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
839 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
840 TRACE(" 0x%x\n",glyphs[glyph_index]);
841 return glyph_index + write_dir;
844 return GSUB_E_NOGLYPH;
847 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
849 int j;
851 TRACE("Ligature Substitution Subtable\n");
852 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
854 const GSUB_LigatureSubstFormat1 *lsf1;
855 int offset,index;
857 offset = GET_BE_WORD(look->SubTable[j]);
858 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
859 offset = GET_BE_WORD(lsf1->Coverage);
860 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
861 TRACE(" Coverage index %i\n",index);
862 if (index != -1)
864 const GSUB_LigatureSet *ls;
865 int k, count;
867 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
868 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
869 count = GET_BE_WORD(ls->LigatureCount);
870 TRACE(" LigatureSet has %i members\n",count);
871 for (k = 0; k < count; k++)
873 const GSUB_Ligature *lig;
874 int CompCount,l,CompIndex;
876 offset = GET_BE_WORD(ls->Ligature[k]);
877 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
878 CompCount = GET_BE_WORD(lig->CompCount) - 1;
879 CompIndex = glyph_index+write_dir;
880 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
882 int CompGlyph;
883 CompGlyph = GET_BE_WORD(lig->Component[l]);
884 if (CompGlyph != glyphs[CompIndex])
885 break;
886 CompIndex += write_dir;
888 if (l == CompCount)
890 int replaceIdx = glyph_index;
891 if (write_dir < 0)
892 replaceIdx = glyph_index - CompCount;
894 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
895 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
896 TRACE("0x%x\n",glyphs[replaceIdx]);
897 if (CompCount > 0)
899 int j;
900 for (j = replaceIdx + 1; j < *glyph_count; j++)
901 glyphs[j] =glyphs[j+CompCount];
902 *glyph_count = *glyph_count - CompCount;
904 return replaceIdx + write_dir;
909 return GSUB_E_NOGLYPH;
912 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
914 int j;
915 BOOL done = FALSE;
917 TRACE("Chaining Contextual Substitution Subtable\n");
918 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
920 const GSUB_ChainContextSubstFormat1 *ccsf1;
921 int offset;
922 int dirLookahead = write_dir;
923 int dirBacktrack = -1 * write_dir;
925 offset = GET_BE_WORD(look->SubTable[j]);
926 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
927 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
929 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
930 continue;
932 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
934 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
935 continue;
937 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
939 int k;
940 int indexGlyphs;
941 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
942 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
943 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
944 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
945 int newIndex = glyph_index;
947 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
949 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
951 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
953 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
954 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
955 break;
957 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
958 continue;
959 TRACE("Matched Backtrack\n");
961 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
963 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
964 for (k = 0; k < indexGlyphs; k++)
966 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
967 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
968 break;
970 if (k != indexGlyphs)
971 continue;
972 TRACE("Matched IndexGlyphs\n");
974 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
976 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
978 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
979 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
980 break;
982 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
983 continue;
984 TRACE("Matched LookAhead\n");
986 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
988 if (GET_BE_WORD(ccsf3_4->SubstCount))
990 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
992 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
993 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
995 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
996 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
997 if (newIndex == -1)
999 ERR("Chain failed to generate a glyph\n");
1000 continue;
1003 return newIndex;
1005 else return GSUB_E_NOGLYPH;
1008 return -1;
1011 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1013 int offset;
1014 const GSUB_LookupTable *look;
1016 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1017 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1018 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1019 switch(GET_BE_WORD(look->LookupType))
1021 case 1:
1022 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1023 case 2:
1024 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1025 case 3:
1026 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1027 case 4:
1028 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1029 case 6:
1030 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1031 default:
1032 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1034 return GSUB_E_NOGLYPH;
1037 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)
1039 int i;
1040 int out_index = GSUB_E_NOGLYPH;
1041 const GSUB_LookupList *lookup;
1043 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1045 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1046 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1048 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1049 if (out_index != GSUB_E_NOGLYPH)
1050 break;
1052 if (out_index == GSUB_E_NOGLYPH)
1053 TRACE("lookups found no glyphs\n");
1054 else
1056 int out2;
1057 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1058 if (out2!=GSUB_E_NOGLYPH)
1059 out_index = out2;
1061 return out_index;
1064 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1066 UINT charset;
1068 if (psc->userScript != 0)
1070 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1071 return ShapingData[psa->eScript].newOtTag;
1072 else
1073 return (char*)&psc->userScript;
1076 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1077 return ShapingData[psa->eScript].newOtTag;
1079 if (ShapingData[psa->eScript].otTag[0] != 0)
1080 return ShapingData[psa->eScript].otTag;
1083 * fall back to the font charset
1085 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1086 switch (charset)
1088 case ANSI_CHARSET: return "latn";
1089 case BALTIC_CHARSET: return "latn"; /* ?? */
1090 case CHINESEBIG5_CHARSET: return "hani";
1091 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1092 case GB2312_CHARSET: return "hani";
1093 case GREEK_CHARSET: return "grek";
1094 case HANGUL_CHARSET: return "hang";
1095 case RUSSIAN_CHARSET: return "cyrl";
1096 case SHIFTJIS_CHARSET: return "kana";
1097 case TURKISH_CHARSET: return "latn"; /* ?? */
1098 case VIETNAMESE_CHARSET: return "latn";
1099 case JOHAB_CHARSET: return "latn"; /* ?? */
1100 case ARABIC_CHARSET: return "arab";
1101 case HEBREW_CHARSET: return "hebr";
1102 case THAI_CHARSET: return "thai";
1103 default: return "latn";
1107 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1109 const GSUB_Feature *feature;
1110 const char* script;
1111 int i;
1113 script = get_opentype_script(hdc,psa,psc,FALSE);
1115 for (i = 0; i < psc->feature_count; i++)
1117 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1118 return psc->features[i].feature;
1121 feature = NULL;
1123 if (psc->GSUB_Table)
1125 const GSUB_Script *script;
1126 const GSUB_LangSys *language;
1127 int attempt = 2;
1131 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1132 attempt--;
1133 if (script)
1135 if (psc->userLang != 0)
1136 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1137 else
1138 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1139 if (language)
1140 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1142 } while(attempt && !feature);
1144 /* try in the default (latin) table */
1145 if (!feature)
1147 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1148 if (script)
1150 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1151 if (language)
1152 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1157 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1159 psc->feature_count++;
1161 if (psc->features)
1162 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1163 else
1164 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1166 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1167 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1168 psc->features[psc->feature_count - 1].feature = feature;
1169 return feature;
1172 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)
1174 const GSUB_Feature *feature;
1176 feature = load_GSUB_feature(hdc, psa, psc, feat);
1177 if (!feature)
1178 return GSUB_E_NOFEATURE;
1180 TRACE("applying feature %s\n",feat);
1181 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1184 static VOID *load_gsub_table(HDC hdc)
1186 VOID* GSUB_Table = NULL;
1187 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1188 if (length != GDI_ERROR)
1190 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1191 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1192 TRACE("Loaded GSUB table of %i bytes\n",length);
1194 return GSUB_Table;
1197 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)
1199 WORD *glyphs;
1200 INT glyph_count = count;
1201 INT rc;
1203 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1204 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1205 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1206 if (rc > GSUB_E_NOGLYPH)
1207 rc = count - glyph_count;
1208 else
1209 rc = 0;
1211 HeapFree(GetProcessHeap(),0,glyphs);
1212 return rc;
1215 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1217 int offset;
1218 WORD class = 0;
1219 const GDEF_ClassDefFormat1 *cf1;
1221 if (!header)
1222 return 0;
1224 offset = GET_BE_WORD(header->GlyphClassDef);
1225 if (!offset)
1226 return 0;
1228 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1229 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1231 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1233 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1234 if (index < GET_BE_WORD(cf1->GlyphCount))
1235 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1238 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1240 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1241 int i, top;
1242 top = GET_BE_WORD(cf2->ClassRangeCount);
1243 for (i = 0; i < top; i++)
1245 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1246 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1248 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1249 break;
1253 else
1254 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1256 return class;
1259 static VOID *load_gdef_table(HDC hdc)
1261 VOID* GDEF_Table = NULL;
1262 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1263 if (length != GDI_ERROR)
1265 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1266 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1267 TRACE("Loaded GDEF table of %i bytes\n",length);
1269 return GDEF_Table;
1272 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
1274 int i;
1276 if (!psc->GDEF_Table)
1277 psc->GDEF_Table = load_gdef_table(hdc);
1279 for (i = 0; i < cGlyphs; i++)
1281 WORD class;
1282 int char_count = 0;
1283 int k;
1285 for (k = 0; k < cChars; k++)
1286 if (pwLogClust[k] == i)
1287 char_count++;
1289 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1291 switch (class)
1293 case 0:
1294 case BaseGlyph:
1295 pGlyphProp[i].sva.fClusterStart = 1;
1296 pGlyphProp[i].sva.fDiacritic = 0;
1297 pGlyphProp[i].sva.fZeroWidth = 0;
1298 break;
1299 case LigatureGlyph:
1300 pGlyphProp[i].sva.fClusterStart = 1;
1301 pGlyphProp[i].sva.fDiacritic = 0;
1302 pGlyphProp[i].sva.fZeroWidth = 0;
1303 break;
1304 case MarkGlyph:
1305 pGlyphProp[i].sva.fClusterStart = 0;
1306 pGlyphProp[i].sva.fDiacritic = 1;
1307 pGlyphProp[i].sva.fZeroWidth = 1;
1308 break;
1309 case ComponentGlyph:
1310 pGlyphProp[i].sva.fClusterStart = 0;
1311 pGlyphProp[i].sva.fDiacritic = 0;
1312 pGlyphProp[i].sva.fZeroWidth = 0;
1313 break;
1314 default:
1315 ERR("Unknown glyph class %i\n",class);
1316 pGlyphProp[i].sva.fClusterStart = 1;
1317 pGlyphProp[i].sva.fDiacritic = 0;
1318 pGlyphProp[i].sva.fZeroWidth = 0;
1321 if (char_count == 0)
1322 pGlyphProp[i].sva.fClusterStart = 0;
1326 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1328 int i;
1330 for (i = 0; i < cGlyphs; i++)
1332 if (!pGlyphProp[i].sva.fClusterStart)
1334 int j;
1335 for (j = 0; j < cChars; j++)
1337 if (pwLogClust[j] == i)
1339 int k = j;
1340 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1341 k-=1;
1342 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1343 pwLogClust[j] = pwLogClust[k];
1350 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1352 if (changeCount == 0)
1353 return;
1354 else
1356 int i;
1357 int target_glyph = nextIndex - write_dir;
1358 int seeking_glyph;
1359 int target_index = -1;
1360 int replacing_glyph = -1;
1361 int changed = 0;
1363 if (changeCount > 0)
1365 if (write_dir > 0)
1366 target_glyph = nextIndex - changeCount;
1367 else
1368 target_glyph = nextIndex + (changeCount + 1);
1371 seeking_glyph = target_glyph;
1373 do {
1374 if (write_dir > 0)
1375 for (i = 0; i < chars; i++)
1377 if (pwLogClust[i] == seeking_glyph)
1379 target_index = i;
1380 break;
1383 else
1384 for (i = chars - 1; i >= 0; i--)
1386 if (pwLogClust[i] == seeking_glyph)
1388 target_index = i;
1389 break;
1392 if (target_index == -1)
1393 seeking_glyph ++;
1395 while (target_index == -1 && seeking_glyph < chars);
1397 if (target_index == -1)
1399 ERR("Unable to find target glyph\n");
1400 return;
1403 if (changeCount < 0)
1405 /* merge glyphs */
1406 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1408 if (pwLogClust[i] == target_glyph)
1409 continue;
1410 if(pwLogClust[i] == replacing_glyph)
1411 pwLogClust[i] = target_glyph;
1412 else
1414 changed--;
1415 if (changed >= changeCount)
1417 replacing_glyph = pwLogClust[i];
1418 pwLogClust[i] = target_glyph;
1420 else
1421 break;
1425 /* renumber trailing indexes*/
1426 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1428 if (pwLogClust[i] != target_glyph)
1429 pwLogClust[i] += changeCount;
1432 else
1434 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1435 pwLogClust[i] += changeCount;
1440 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 )
1442 if (psc->GSUB_Table)
1444 const GSUB_Feature *feature;
1445 const GSUB_LookupList *lookup;
1446 const GSUB_Header *header = psc->GSUB_Table;
1447 int lookup_index, lookup_count;
1449 feature = load_GSUB_feature(hdc, psa, psc, feat);
1450 if (!feature)
1451 return GSUB_E_NOFEATURE;
1453 TRACE("applying feature %s\n",debugstr_an(feat,4));
1454 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1455 lookup_count = GET_BE_WORD(feature->LookupCount);
1456 TRACE("%i lookups\n", lookup_count);
1457 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1459 int i;
1461 if (write_dir > 0)
1462 i = 0;
1463 else
1464 i = *pcGlyphs-1;
1465 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1466 while(i < *pcGlyphs && i >= 0)
1468 INT nextIndex;
1469 INT prevCount = *pcGlyphs;
1471 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1472 if (*pcGlyphs != prevCount)
1474 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1475 i = nextIndex;
1477 else
1478 i+=write_dir;
1481 return *pcGlyphs;
1483 return GSUB_E_NOFEATURE;
1486 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1488 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1491 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1493 if (i + delta < 0)
1494 return 0;
1495 if ( i+ delta >= cchLen)
1496 return 0;
1498 i += delta;
1500 return chars[i];
1503 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1505 if (i + delta < 0)
1507 if (psa->fLinkBefore)
1508 return jtR;
1509 else
1510 return jtU;
1512 if ( i+ delta >= cchLen)
1514 if (psa->fLinkAfter)
1515 return jtL;
1516 else
1517 return jtU;
1520 i += delta;
1522 if (context_type[i] == jtT)
1523 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1524 else
1525 return context_type[i];
1528 static inline BOOL right_join_causing(CHAR joining_type)
1530 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1533 static inline BOOL left_join_causing(CHAR joining_type)
1535 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1538 static inline BOOL word_break_causing(WCHAR chr)
1540 /* we are working within a string of characters already guareented to
1541 be within one script, Syriac, so we do not worry about any character
1542 other than the space character outside of that range */
1543 return (chr == 0 || chr == 0x20 );
1547 * ContextualShape_Arabic
1549 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1551 CHAR *context_type;
1552 INT *context_shape;
1553 INT dirR, dirL;
1554 int i;
1556 if (*pcGlyphs != cChars)
1558 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1559 return;
1562 if (!psa->fLogicalOrder && psa->fRTL)
1564 dirR = 1;
1565 dirL = -1;
1567 else
1569 dirR = -1;
1570 dirL = 1;
1573 if (!psc->GSUB_Table)
1574 psc->GSUB_Table = load_gsub_table(hdc);
1576 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1577 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1579 for (i = 0; i < cChars; i++)
1580 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1582 for (i = 0; i < cChars; i++)
1584 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1585 context_shape[i] = Xr;
1586 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1587 context_shape[i] = Xl;
1588 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)))
1589 context_shape[i] = Xm;
1590 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1591 context_shape[i] = Xr;
1592 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1593 context_shape[i] = Xl;
1594 else
1595 context_shape[i] = Xn;
1598 /* Contextual Shaping */
1599 i = 0;
1600 while(i < *pcGlyphs)
1602 BOOL shaped = FALSE;
1604 if (psc->GSUB_Table)
1606 INT nextIndex;
1607 INT prevCount = *pcGlyphs;
1608 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1609 if (nextIndex > GSUB_E_NOGLYPH)
1611 i = nextIndex;
1612 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1614 shaped = (nextIndex > GSUB_E_NOGLYPH);
1617 if (!shaped)
1619 if (context_shape[i] == Xn)
1621 WORD newGlyph = pwOutGlyphs[i];
1622 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1624 /* fall back to presentation form B */
1625 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1626 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1627 pwOutGlyphs[i] = newGlyph;
1630 i++;
1634 HeapFree(GetProcessHeap(),0,context_shape);
1635 HeapFree(GetProcessHeap(),0,context_type);
1639 * ContextualShape_Syriac
1642 #define ALAPH 0x710
1643 #define DALATH 0x715
1644 #define RISH 0x72A
1646 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1648 CHAR *context_type;
1649 INT *context_shape;
1650 INT dirR, dirL;
1651 int i;
1653 if (*pcGlyphs != cChars)
1655 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1656 return;
1659 if (!psa->fLogicalOrder && psa->fRTL)
1661 dirR = 1;
1662 dirL = -1;
1664 else
1666 dirR = -1;
1667 dirL = 1;
1670 if (!psc->GSUB_Table)
1671 psc->GSUB_Table = load_gsub_table(hdc);
1673 if (!psc->GSUB_Table)
1674 return;
1676 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1677 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1679 for (i = 0; i < cChars; i++)
1680 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1682 for (i = 0; i < cChars; i++)
1684 if (pwcChars[i] == ALAPH)
1686 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1688 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1689 context_shape[i] = Afj;
1690 else if ( rchar != DALATH && rchar != RISH &&
1691 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1692 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1693 context_shape[i] = Afn;
1694 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1695 context_shape[i] = Afx;
1696 else
1697 context_shape[i] = Xn;
1699 else if (context_type[i] == jtR &&
1700 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1701 context_shape[i] = Xr;
1702 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1703 context_shape[i] = Xl;
1704 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)))
1705 context_shape[i] = Xm;
1706 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1707 context_shape[i] = Xr;
1708 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1709 context_shape[i] = Xl;
1710 else
1711 context_shape[i] = Xn;
1714 /* Contextual Shaping */
1715 i = 0;
1716 while(i < *pcGlyphs)
1718 INT nextIndex;
1719 INT prevCount = *pcGlyphs;
1720 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1721 if (nextIndex > GSUB_E_NOGLYPH)
1723 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1724 i = nextIndex;
1726 else
1727 i++;
1730 HeapFree(GetProcessHeap(),0,context_shape);
1731 HeapFree(GetProcessHeap(),0,context_type);
1735 * ContextualShape_Phags_pa
1738 #define phags_pa_CANDRABINDU 0xA873
1739 #define phags_pa_START 0xA840
1740 #define phags_pa_END 0xA87F
1742 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1744 INT *context_shape;
1745 INT dirR, dirL;
1746 int i;
1748 if (*pcGlyphs != cChars)
1750 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1751 return;
1754 if (!psa->fLogicalOrder && psa->fRTL)
1756 dirR = 1;
1757 dirL = -1;
1759 else
1761 dirR = -1;
1762 dirL = 1;
1765 if (!psc->GSUB_Table)
1766 psc->GSUB_Table = load_gsub_table(hdc);
1768 if (!psc->GSUB_Table)
1769 return;
1771 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1773 for (i = 0; i < cChars; i++)
1775 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1777 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1778 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1779 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1780 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1782 if (jrchar && jlchar)
1783 context_shape[i] = Xm;
1784 else if (jrchar)
1785 context_shape[i] = Xr;
1786 else if (jlchar)
1787 context_shape[i] = Xl;
1788 else
1789 context_shape[i] = Xn;
1791 else
1792 context_shape[i] = -1;
1795 /* Contextual Shaping */
1796 i = 0;
1797 while(i < *pcGlyphs)
1799 if (context_shape[i] >= 0)
1801 INT nextIndex;
1802 INT prevCount = *pcGlyphs;
1803 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1804 if (nextIndex > GSUB_E_NOGLYPH)
1806 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1807 i = nextIndex;
1809 else
1810 i++;
1812 else
1813 i++;
1816 HeapFree(GetProcessHeap(),0,context_shape);
1819 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1821 int i;
1823 /* Replace */
1824 pwOutChars[cWalk] = replacements[0];
1825 cWalk=cWalk+1;
1827 /* Insert */
1828 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1830 int j;
1831 for (j = *pcChars; j > cWalk; j--)
1832 pwOutChars[j] = pwOutChars[j-1];
1833 *pcChars= *pcChars+1;
1834 pwOutChars[cWalk] = replacements[i];
1835 cWalk = cWalk+1;
1839 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust)
1841 int i;
1842 int cWalk;
1843 int offset = 0;
1845 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1847 for (i = 0; vowels[i].base != 0x0; i++)
1849 if (pwOutChars[cWalk] == vowels[i].base)
1851 int j;
1852 int o = 1;
1853 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1854 if (vowels[i].parts[1]) { cWalk++; o++; }
1855 if (vowels[i].parts[2]) { cWalk++; o++; }
1856 offset += o;
1857 for (j = (cWalk - offset) + 1; j < *pcChars - offset; j ++)
1858 pwLogClust[j]+=o;
1859 break;
1865 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1867 int i;
1868 int offset = 0;
1869 int cWalk;
1871 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1873 for (i = 0; consonants[i].output!= 0x0; i++)
1875 int j;
1876 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1877 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1878 break;
1880 if (consonants[i].parts[j]==0x0) /* matched all */
1882 int k;
1883 j--;
1884 pwOutChars[cWalk] = consonants[i].output;
1885 for(k = cWalk+1; k < *pcChars - j; k++)
1886 pwOutChars[k] = pwOutChars[k+j];
1887 *pcChars = *pcChars - j;
1888 for (k = j ; k > 0; k--)
1889 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1890 offset += j;
1891 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1892 pwLogClust[k]--;
1893 break;
1896 cWalk++;
1900 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1902 if (s->ralf >= 0)
1904 int j;
1905 WORD Ra = pwChar[s->start];
1906 WORD H = pwChar[s->start+1];
1908 TRACE("Doing reorder of Ra to %i\n",s->base);
1909 for (j = s->start; j < s->base-1; j++)
1910 pwChar[j] = pwChar[j+2];
1911 pwChar[s->base-1] = Ra;
1912 pwChar[s->base] = H;
1914 s->ralf = s->base-1;
1915 s->base -= 2;
1919 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1921 if (s->ralf >= 0)
1923 int j,loc;
1924 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1925 WORD Ra = pwChar[s->start];
1926 WORD H = pwChar[s->start+1];
1927 for (loc = s->end; loc > stop; loc--)
1928 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1929 break;
1931 TRACE("Doing reorder of Ra to %i\n",loc);
1932 for (j = s->start; j < loc-1; j++)
1933 pwChar[j] = pwChar[j+2];
1934 pwChar[loc-1] = Ra;
1935 pwChar[loc] = H;
1937 s->ralf = loc-1;
1938 s->base -= 2;
1939 if (s->blwf >= 0) s->blwf -= 2;
1940 if (s->pref >= 0) s->pref -= 2;
1944 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1946 if (s->ralf >= 0)
1948 int j;
1949 WORD Ra = pwChar[s->start];
1950 WORD H = pwChar[s->start+1];
1952 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1953 for (j = s->start; j < s->end-1; j++)
1954 pwChar[j] = pwChar[j+2];
1955 pwChar[s->end-1] = Ra;
1956 pwChar[s->end] = H;
1958 s->ralf = s->end-1;
1959 s->base -= 2;
1960 if (s->blwf >= 0) s->blwf -= 2;
1961 if (s->pref >= 0) s->pref -= 2;
1965 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1967 int i;
1969 /* reorder Matras */
1970 if (s->end > s->base)
1972 for (i = 1; i <= s->end-s->base; i++)
1974 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1976 int j;
1977 WCHAR c = pwChar[s->base+i];
1978 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1979 for (j = s->base+i; j > s->base; j--)
1980 pwChar[j] = pwChar[j-1];
1981 pwChar[s->base] = c;
1983 if (s->ralf >= s->base) s->ralf++;
1984 if (s->blwf >= s->base) s->blwf++;
1985 if (s->pref >= s->base) s->pref++;
1986 s->base ++;
1992 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1994 int i;
1996 /* reorder Matras */
1997 if (s->end > s->base)
1999 for (i = 1; i <= s->end-s->base; i++)
2001 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2003 int j;
2004 WCHAR c = pwChar[s->base+i];
2005 TRACE("Doing reorder of %x to %i\n",c,s->start);
2006 for (j = s->base+i; j > s->start; j--)
2007 pwChar[j] = pwChar[j-1];
2008 pwChar[s->start] = c;
2010 if (s->ralf >= 0) s->ralf++;
2011 if (s->blwf >= 0) s->blwf++;
2012 if (s->pref >= 0) s->pref++;
2013 s->base ++;
2019 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2021 if (s->blwf >= 0 && g->blwf > g->base)
2023 int j,loc;
2024 int g_offset;
2025 for (loc = s->end; loc > s->blwf; loc--)
2026 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2027 break;
2029 g_offset = (loc - s->blwf) - 1;
2031 if (loc != s->blwf)
2033 WORD blwf = glyphs[g->blwf];
2034 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2035 /* do not care about the pwChar array anymore, just the glyphs */
2036 for (j = 0; j < g_offset; j++)
2037 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2038 glyphs[g->blwf + g_offset] = blwf;
2043 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2045 int i;
2047 /* reorder previously moved Matras to correct position*/
2048 for (i = s->start; i < s->base; i++)
2050 if (lexical(pwChar[i]) == lex_Matra_pre)
2052 int j;
2053 int g_start = g->start + i - s->start;
2054 if (g_start < g->base -1 )
2056 WCHAR og = glyphs[g_start];
2057 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2058 for (j = g_start; j < g->base-1; j++)
2059 glyphs[j] = glyphs[j+1];
2060 glyphs[g->base-1] = og;
2066 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2068 if (s->pref >= 0 && g->pref > g->base)
2070 int j;
2071 WCHAR og = glyphs[g->pref];
2072 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2073 for (j = g->pref; j > g->base; j--)
2074 glyphs[j] = glyphs[j-1];
2075 glyphs[g->base] = og;
2079 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2081 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2082 if (s->start == s->base && s->base == s->end) return;
2083 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2085 Reorder_Ra_follows_base(pwChar, s, lexical);
2086 Reorder_Matra_precede_base(pwChar, s, lexical);
2089 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2091 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2092 if (s->start == s->base && s->base == s->end) return;
2093 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2095 Reorder_Ra_follows_matra(pwChar, s, lexical);
2096 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2099 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2101 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2102 if (s->start == s->base && s->base == s->end) return;
2103 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2105 Reorder_Ra_follows_base(pwChar, s, lexical);
2106 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2109 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2111 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2112 if (s->start == s->base && s->base == s->end) return;
2113 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2115 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2116 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2119 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2121 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2122 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2123 if (s->start == s->base && s->base == s->end) return;
2124 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2126 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2129 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2131 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2132 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2133 if (s->start == s->base && s->base == s->end) return;
2134 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2136 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2137 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2141 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2143 if (shift == 0)
2144 return;
2146 if (glyph_index->start > index)
2147 glyph_index->start += shift;
2148 if (glyph_index->base > index)
2149 glyph_index->base+= shift;
2150 if (glyph_index->end > index)
2151 glyph_index->end+= shift;
2152 if (glyph_index->ralf > index)
2153 glyph_index->ralf+= shift;
2154 if (glyph_index->blwf > index)
2155 glyph_index->blwf+= shift;
2156 if (glyph_index->pref > index)
2157 glyph_index->pref+= shift;
2160 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 )
2162 int index = glyph_index->start;
2164 if (!feature)
2165 return;
2167 while(index <= glyph_index->end)
2169 INT nextIndex;
2170 INT prevCount = *pcGlyphs;
2171 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2172 if (nextIndex > GSUB_E_NOGLYPH)
2174 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2175 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2176 index = nextIndex;
2178 else
2179 index++;
2183 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2185 int i = 0;
2186 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)))))
2187 i++;
2188 if (index + i <= end-1)
2189 return index + i;
2190 else
2191 return -1;
2194 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)
2196 INT index, nextIndex;
2197 INT count,g_offset;
2199 count = syllable->base - syllable->start;
2201 g_offset = 0;
2202 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2203 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2205 INT prevCount = *pcGlyphs;
2206 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2207 if (nextIndex > GSUB_E_NOGLYPH)
2209 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2210 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2211 g_offset += (*pcGlyphs - prevCount);
2214 index+=2;
2215 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2219 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)
2221 INT nextIndex;
2222 INT prevCount = *pcGlyphs;
2224 if (syllable->ralf >= 0)
2226 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2227 if (nextIndex > GSUB_E_NOGLYPH)
2229 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2230 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2235 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2237 int i = 0;
2238 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2239 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2240 is_consonant(lexical(pwChars[index+i+1])))))
2241 i++;
2242 if (index + i <= end-1)
2243 return index+i;
2244 else
2245 return -1;
2248 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)
2250 INT index, nextIndex;
2251 INT count, g_offset=0;
2252 INT ralf = syllable->ralf;
2254 count = syllable->end - syllable->base;
2256 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2258 while (index >= 0)
2260 INT prevCount = *pcGlyphs;
2261 if (ralf >=0 && ralf < index)
2263 g_offset--;
2264 ralf = -1;
2267 if (!modern)
2269 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2270 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2271 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2274 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2275 if (nextIndex > GSUB_E_NOGLYPH)
2277 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2278 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2279 g_offset += (*pcGlyphs - prevCount);
2281 else if (!modern)
2283 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2284 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2285 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2288 index+=2;
2289 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2293 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)
2295 int c;
2296 int overall_shift = 0;
2297 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2298 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2299 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2300 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2301 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2302 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2303 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2304 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2305 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2306 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2307 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2308 IndicSyllable glyph_indexs;
2310 for (c = 0; c < syllable_count; c++)
2312 int old_end;
2313 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2314 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2315 old_end = glyph_indexs.end;
2317 if (locl)
2319 TRACE("applying feature locl\n");
2320 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2322 if (nukt)
2324 TRACE("applying feature nukt\n");
2325 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2327 if (akhn)
2329 TRACE("applying feature akhn\n");
2330 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2333 if (rphf)
2334 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2335 if (rkrf)
2337 TRACE("applying feature rkrf\n");
2338 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2340 if (pref)
2341 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2342 if (blwf)
2344 if (!modern)
2345 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2347 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2350 if (half)
2351 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2352 if (pstf)
2354 TRACE("applying feature pstf\n");
2355 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2357 if (vatu)
2359 TRACE("applying feature vatu\n");
2360 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2362 if (cjct)
2364 TRACE("applying feature cjct\n");
2365 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2368 if (second_reorder)
2369 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2371 overall_shift += glyph_indexs.end - old_end;
2375 static inline int unicode_lex(WCHAR c)
2377 int type;
2379 if (!c) return lex_Generic;
2380 if (c == 0x200D) return lex_ZWJ;
2381 if (c == 0x200C) return lex_ZWNJ;
2382 if (c == 0x00A0) return lex_NBSP;
2384 type = get_table_entry( indic_syllabic_table, c );
2386 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2388 switch( type )
2390 case 0x0d07: /* Unknown */
2391 case 0x0e07: /* Unknwon */
2392 default: return lex_Generic;
2393 case 0x0001:
2394 case 0x0002:
2395 case 0x0011:
2396 case 0x0012:
2397 case 0x0013:
2398 case 0x0014: return lex_Modifier;
2399 case 0x0003:
2400 case 0x0009:
2401 case 0x000a:
2402 case 0x000b:
2403 case 0x000d:
2404 case 0x000e:
2405 case 0x000f:
2406 case 0x0010: return lex_Consonant;
2407 case 0x0004: return lex_Nukta;
2408 case 0x0005: return lex_Halant;
2409 case 0x0006:
2410 case 0x0008: return lex_Vowel;
2411 case 0x0007:
2412 case 0x0107: return lex_Matra_post;
2413 case 0x0207:
2414 case 0x0307: return lex_Matra_pre;
2415 case 0x0807:
2416 case 0x0907:
2417 case 0x0a07:
2418 case 0x0b07:
2419 case 0x0c07:
2420 case 0x0407: return lex_Composed_Vowel;
2421 case 0x0507: return lex_Matra_above;
2422 case 0x0607: return lex_Matra_below;
2423 case 0x000c: return lex_Ra;
2427 static int sinhala_lex(WCHAR c)
2429 switch (c)
2431 case 0x0DDA:
2432 case 0x0DDD:
2433 case 0x0DDC:
2434 case 0x0DDE: return lex_Matra_post;
2435 default:
2436 return unicode_lex(c);
2440 static const VowelComponents Sinhala_vowels[] = {
2441 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2442 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2443 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2444 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2445 {0x0000, {0x0000,0x0000,0x0}}};
2447 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2449 int cCount = cChars;
2450 int i;
2451 WCHAR *input;
2452 IndicSyllable *syllables = NULL;
2453 int syllable_count = 0;
2455 if (*pcGlyphs != cChars)
2457 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2458 return;
2461 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2463 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2465 /* Step 1: Decompose multi part vowels */
2466 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust);
2468 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2470 /* Step 2: Reorder within Syllables */
2471 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2472 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2474 /* Step 3: Strip dangling joiners */
2475 for (i = 0; i < cCount; i++)
2477 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2478 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2479 input[i] = 0x0020;
2482 /* Step 4: Base Form application to syllables */
2483 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2484 *pcGlyphs = cCount;
2485 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2487 HeapFree(GetProcessHeap(),0,input);
2488 HeapFree(GetProcessHeap(),0,syllables);
2491 static int devanagari_lex(WCHAR c)
2493 switch (c)
2495 case 0x0930: return lex_Ra;
2496 default:
2497 return unicode_lex(c);
2501 static const ConsonantComponents Devanagari_consonants[] ={
2502 {{0x0928, 0x093C, 0x00000}, 0x0929},
2503 {{0x0930, 0x093C, 0x00000}, 0x0931},
2504 {{0x0933, 0x093C, 0x00000}, 0x0934},
2505 {{0x0915, 0x093C, 0x00000}, 0x0958},
2506 {{0x0916, 0x093C, 0x00000}, 0x0959},
2507 {{0x0917, 0x093C, 0x00000}, 0x095A},
2508 {{0x091C, 0x093C, 0x00000}, 0x095B},
2509 {{0x0921, 0x093C, 0x00000}, 0x095C},
2510 {{0x0922, 0x093C, 0x00000}, 0x095D},
2511 {{0x092B, 0x093C, 0x00000}, 0x095E},
2512 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2514 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2516 int cCount = cChars;
2517 WCHAR *input;
2518 IndicSyllable *syllables = NULL;
2519 int syllable_count = 0;
2520 BOOL modern = get_GSUB_Indic2(psa, psc);
2522 if (*pcGlyphs != cChars)
2524 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2525 return;
2528 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2529 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2531 /* Step 1: Compose Consonant and Nukta */
2532 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2533 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2535 /* Step 2: Reorder within Syllables */
2536 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2537 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2538 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2539 *pcGlyphs = cCount;
2541 /* Step 3: Base Form application to syllables */
2542 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2544 HeapFree(GetProcessHeap(),0,input);
2545 HeapFree(GetProcessHeap(),0,syllables);
2548 static int bengali_lex(WCHAR c)
2550 switch (c)
2552 case 0x09B0: return lex_Ra;
2553 default:
2554 return unicode_lex(c);
2558 static const VowelComponents Bengali_vowels[] = {
2559 {0x09CB, {0x09C7,0x09BE,0x0000}},
2560 {0x09CC, {0x09C7,0x09D7,0x0000}},
2561 {0x0000, {0x0000,0x0000,0x0000}}};
2563 static const ConsonantComponents Bengali_consonants[] = {
2564 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2565 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2566 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2567 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2568 {{0x0000,0x0000,0x0000}, 0x0000}};
2570 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2572 int cCount = cChars;
2573 WCHAR *input;
2574 IndicSyllable *syllables = NULL;
2575 int syllable_count = 0;
2576 BOOL modern = get_GSUB_Indic2(psa, psc);
2578 if (*pcGlyphs != cChars)
2580 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2581 return;
2584 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2585 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2587 /* Step 1: Decompose Vowels and Compose Consonents */
2588 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust);
2589 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2590 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2592 /* Step 2: Reorder within Syllables */
2593 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2594 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2595 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2596 *pcGlyphs = cCount;
2598 /* Step 3: Initial form is only applied to the beginning of words */
2599 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2601 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2603 int index = cCount;
2604 int gCount = 1;
2605 if (index > 0) index++;
2607 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2611 /* Step 4: Base Form application to syllables */
2612 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2614 HeapFree(GetProcessHeap(),0,input);
2615 HeapFree(GetProcessHeap(),0,syllables);
2618 static int gurmukhi_lex(WCHAR c)
2620 if (c == 0x0A71)
2621 return lex_Modifier;
2622 else
2623 return unicode_lex(c);
2626 static const ConsonantComponents Gurmukhi_consonants[] = {
2627 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2628 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2629 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2630 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2631 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2632 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2633 {{0x0000,0x0000,0x0000}, 0x0000}};
2635 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2637 int cCount = cChars;
2638 WCHAR *input;
2639 IndicSyllable *syllables = NULL;
2640 int syllable_count = 0;
2641 BOOL modern = get_GSUB_Indic2(psa, psc);
2643 if (*pcGlyphs != cChars)
2645 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2646 return;
2649 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2650 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2652 /* Step 1: Compose Consonents */
2653 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2654 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2656 /* Step 2: Reorder within Syllables */
2657 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2658 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2659 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2660 *pcGlyphs = cCount;
2662 /* Step 3: Base Form application to syllables */
2663 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2665 HeapFree(GetProcessHeap(),0,input);
2666 HeapFree(GetProcessHeap(),0,syllables);
2669 static int gujarati_lex(WCHAR c)
2671 switch (c)
2673 case 0x0AB0: return lex_Ra;
2674 default:
2675 return unicode_lex(c);
2679 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2681 int cCount = cChars;
2682 WCHAR *input;
2683 IndicSyllable *syllables = NULL;
2684 int syllable_count = 0;
2685 BOOL modern = get_GSUB_Indic2(psa, psc);
2687 if (*pcGlyphs != cChars)
2689 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2690 return;
2693 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2694 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2696 /* Step 1: Reorder within Syllables */
2697 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2698 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2699 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2700 *pcGlyphs = cCount;
2702 /* Step 2: Base Form application to syllables */
2703 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2705 HeapFree(GetProcessHeap(),0,input);
2706 HeapFree(GetProcessHeap(),0,syllables);
2709 static int oriya_lex(WCHAR c)
2711 switch (c)
2713 case 0x0B30: return lex_Ra;
2714 default:
2715 return unicode_lex(c);
2719 static const VowelComponents Oriya_vowels[] = {
2720 {0x0B48, {0x0B47,0x0B56,0x0000}},
2721 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2722 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2723 {0x0000, {0x0000,0x0000,0x0000}}};
2725 static const ConsonantComponents Oriya_consonants[] = {
2726 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2727 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2728 {{0x0000,0x0000,0x0000}, 0x0000}};
2730 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2732 int cCount = cChars;
2733 WCHAR *input;
2734 IndicSyllable *syllables = NULL;
2735 int syllable_count = 0;
2736 BOOL modern = get_GSUB_Indic2(psa, psc);
2738 if (*pcGlyphs != cChars)
2740 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2741 return;
2744 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2745 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2747 /* Step 1: Decompose Vowels and Compose Consonents */
2748 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust);
2749 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2750 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2752 /* Step 2: Reorder within Syllables */
2753 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2754 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2755 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2756 *pcGlyphs = cCount;
2758 /* Step 3: Base Form application to syllables */
2759 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2761 HeapFree(GetProcessHeap(),0,input);
2762 HeapFree(GetProcessHeap(),0,syllables);
2765 static int tamil_lex(WCHAR c)
2767 return unicode_lex(c);
2770 static const VowelComponents Tamil_vowels[] = {
2771 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2772 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2773 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2774 {0x0000, {0x0000,0x0000,0x0000}}};
2776 static const ConsonantComponents Tamil_consonants[] = {
2777 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2778 {{0x0000,0x0000,0x0000}, 0x0000}};
2780 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2782 int cCount = cChars;
2783 WCHAR *input;
2784 IndicSyllable *syllables = NULL;
2785 int syllable_count = 0;
2786 BOOL modern = get_GSUB_Indic2(psa, psc);
2788 if (*pcGlyphs != cChars)
2790 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2791 return;
2794 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2795 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2797 /* Step 1: Decompose Vowels and Compose Consonents */
2798 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust);
2799 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2800 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2802 /* Step 2: Reorder within Syllables */
2803 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2804 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2805 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2806 *pcGlyphs = cCount;
2808 /* Step 3: Base Form application to syllables */
2809 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2811 HeapFree(GetProcessHeap(),0,input);
2812 HeapFree(GetProcessHeap(),0,syllables);
2815 static int telugu_lex(WCHAR c)
2817 switch (c)
2819 case 0x0C43:
2820 case 0x0C44: return lex_Modifier;
2821 default:
2822 return unicode_lex(c);
2826 static const VowelComponents Telugu_vowels[] = {
2827 {0x0C48, {0x0C46,0x0C56,0x0000}},
2828 {0x0000, {0x0000,0x0000,0x0000}}};
2830 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2832 int cCount = cChars;
2833 WCHAR *input;
2834 IndicSyllable *syllables = NULL;
2835 int syllable_count = 0;
2836 BOOL modern = get_GSUB_Indic2(psa, psc);
2838 if (*pcGlyphs != cChars)
2840 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2841 return;
2844 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2845 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2847 /* Step 1: Decompose Vowels */
2848 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust);
2849 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2851 /* Step 2: Reorder within Syllables */
2852 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2853 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2854 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2855 *pcGlyphs = cCount;
2857 /* Step 3: Base Form application to syllables */
2858 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2860 HeapFree(GetProcessHeap(),0,input);
2861 HeapFree(GetProcessHeap(),0,syllables);
2864 static int kannada_lex(WCHAR c)
2866 switch (c)
2868 case 0x0CB0: return lex_Ra;
2869 default:
2870 return unicode_lex(c);
2874 static const VowelComponents Kannada_vowels[] = {
2875 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2876 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2877 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2878 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2879 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2880 {0x0000, {0x0000,0x0000,0x0000}}};
2882 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2884 int cCount = cChars;
2885 WCHAR *input;
2886 IndicSyllable *syllables = NULL;
2887 int syllable_count = 0;
2888 BOOL modern = get_GSUB_Indic2(psa, psc);
2890 if (*pcGlyphs != cChars)
2892 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2893 return;
2896 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2897 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2899 /* Step 1: Decompose Vowels */
2900 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust);
2901 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2903 /* Step 2: Reorder within Syllables */
2904 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2905 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2906 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2907 *pcGlyphs = cCount;
2909 /* Step 3: Base Form application to syllables */
2910 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2912 HeapFree(GetProcessHeap(),0,input);
2913 HeapFree(GetProcessHeap(),0,syllables);
2916 static int malayalam_lex(WCHAR c)
2918 return unicode_lex(c);
2921 static const VowelComponents Malayalam_vowels[] = {
2922 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2923 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2924 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2925 {0x0000, {0x0000,0x0000,0x0000}}};
2927 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2929 int cCount = cChars;
2930 WCHAR *input;
2931 IndicSyllable *syllables = NULL;
2932 int syllable_count = 0;
2933 BOOL modern = get_GSUB_Indic2(psa, psc);
2935 if (*pcGlyphs != cChars)
2937 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2938 return;
2941 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2942 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2944 /* Step 1: Decompose Vowels */
2945 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust);
2946 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2948 /* Step 2: Reorder within Syllables */
2949 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2950 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2951 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2952 *pcGlyphs = cCount;
2954 /* Step 3: Base Form application to syllables */
2955 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2957 HeapFree(GetProcessHeap(),0,input);
2958 HeapFree(GetProcessHeap(),0,syllables);
2961 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)
2963 int i,k;
2965 for (i = 0; i < cGlyphs; i++)
2967 int char_index[20];
2968 int char_count = 0;
2970 for (k = 0; k < cChars; k++)
2972 if (pwLogClust[k] == i)
2974 char_index[char_count] = k;
2975 char_count++;
2979 if (char_count == 0)
2980 continue;
2982 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2984 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2985 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2987 else
2988 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2991 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2992 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2995 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 )
2997 int i,k;
2998 int initGlyph, finaGlyph;
2999 INT dirR, dirL;
3000 BYTE *spaces;
3002 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3003 memset(spaces,0,cGlyphs);
3005 if (!psa->fLogicalOrder && psa->fRTL)
3007 initGlyph = cGlyphs-1;
3008 finaGlyph = 0;
3009 dirR = 1;
3010 dirL = -1;
3012 else
3014 initGlyph = 0;
3015 finaGlyph = cGlyphs-1;
3016 dirR = -1;
3017 dirL = 1;
3020 for (i = 0; i < cGlyphs; i++)
3022 for (k = 0; k < cChars; k++)
3023 if (pwLogClust[k] == i)
3025 if (pwcChars[k] == 0x0020)
3026 spaces[i] = 1;
3030 for (i = 0; i < cGlyphs; i++)
3032 int char_index[20];
3033 int char_count = 0;
3034 BOOL isInit, isFinal;
3036 for (k = 0; k < cChars; k++)
3038 if (pwLogClust[k] == i)
3040 char_index[char_count] = k;
3041 char_count++;
3045 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3046 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3048 if (char_count == 0)
3049 continue;
3051 if (char_count == 1)
3053 if (pwcChars[char_index[0]] == 0x0020) /* space */
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3056 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3058 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3059 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3060 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3062 if (!isInit && !isFinal)
3063 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3064 else if (isInit)
3065 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3066 else
3067 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3069 else if (!isInit)
3071 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3072 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3073 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3074 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3075 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3076 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3077 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3078 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3079 else
3080 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3082 else if (!isInit && !isFinal)
3083 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3084 else
3085 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3087 else if (char_count == 2)
3089 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3090 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3091 else if (!isInit)
3092 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3093 else
3094 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3096 else if (!isInit && !isFinal)
3097 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3098 else
3099 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3102 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3103 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3104 HeapFree(GetProcessHeap(),0,spaces);
3107 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 )
3109 int i,k;
3110 int finaGlyph;
3111 INT dirL;
3112 BYTE *spaces;
3114 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3115 memset(spaces,0,cGlyphs);
3117 if (!psa->fLogicalOrder && psa->fRTL)
3119 finaGlyph = 0;
3120 dirL = -1;
3122 else
3124 finaGlyph = cGlyphs-1;
3125 dirL = 1;
3128 for (i = 0; i < cGlyphs; i++)
3130 for (k = 0; k < cChars; k++)
3131 if (pwLogClust[k] == i)
3133 if (pwcChars[k] == 0x0020)
3134 spaces[i] = 1;
3138 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3140 for (i = 0; i < cGlyphs; i++)
3142 int char_index[20];
3143 int char_count = 0;
3145 for (k = 0; k < cChars; k++)
3147 if (pwLogClust[k] == i)
3149 char_index[char_count] = k;
3150 char_count++;
3154 if (char_count == 0)
3155 continue;
3157 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3159 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3160 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3162 else if (i == finaGlyph)
3163 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3164 else
3165 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3167 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3168 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3169 pGlyphProp[i].sva.fClusterStart = 0;
3172 HeapFree(GetProcessHeap(),0,spaces);
3173 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3175 /* Do not allow justification between marks and their base */
3176 for (i = 0; i < cGlyphs; i++)
3178 if (!pGlyphProp[i].sva.fClusterStart)
3179 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3183 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)
3185 int i,k;
3187 for (i = 0; i < cGlyphs; i++)
3189 int char_index[20];
3190 int char_count = 0;
3192 for (k = 0; k < cChars; k++)
3194 if (pwLogClust[k] == i)
3196 char_index[char_count] = k;
3197 char_count++;
3201 if (char_count == 0)
3202 continue;
3204 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3206 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3207 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3209 else
3210 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3212 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3213 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3216 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)
3218 int i,k;
3220 for (i = 0; i < cGlyphs; i++)
3222 int char_index[20];
3223 int char_count = 0;
3225 for (k = 0; k < cChars; k++)
3227 if (pwLogClust[k] == i)
3229 char_index[char_count] = k;
3230 char_count++;
3234 if (char_count == 0)
3235 continue;
3237 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3239 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3240 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3242 else
3243 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3245 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3246 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3248 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3249 for (i = 0; i < cGlyphs; i++)
3251 if (!pGlyphProp[i].sva.fClusterStart)
3253 pGlyphProp[i].sva.fDiacritic = 0;
3254 pGlyphProp[i].sva.fZeroWidth = 0;
3259 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)
3261 int i,k;
3262 IndicSyllable *syllables = NULL;
3263 int syllable_count = 0;
3264 BOOL modern = get_GSUB_Indic2(psa, psc);
3266 for (i = 0; i < cGlyphs; i++)
3268 int char_index[20];
3269 int char_count = 0;
3271 for (k = 0; k < cChars; k++)
3273 if (pwLogClust[k] == i)
3275 char_index[char_count] = k;
3276 char_count++;
3280 if (char_count == 0)
3282 FIXME("No chars in this glyph? Must be an error\n");
3283 continue;
3286 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3288 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3289 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3291 else
3292 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3294 pGlyphProp[i].sva.fClusterStart = 0;
3295 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3296 switch (lexical(pwcChars[char_index[k]]))
3298 case lex_Matra_pre:
3299 case lex_Matra_post:
3300 case lex_Matra_above:
3301 case lex_Matra_below:
3302 case lex_Modifier:
3303 break;
3304 default:
3305 pGlyphProp[i].sva.fClusterStart = 1;
3306 break;
3310 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3312 for (i = 0; i < syllable_count; i++)
3314 int j;
3315 WORD g = pwLogClust[syllables[i].start];
3316 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3318 if (pwLogClust[j] != g)
3320 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3321 pwLogClust[j] = g;
3326 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3327 HeapFree(GetProcessHeap(), 0, syllables);
3330 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 )
3332 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex);
3335 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 )
3337 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3340 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 )
3342 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3345 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 )
3347 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3350 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 )
3352 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3355 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 )
3357 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3360 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 )
3362 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3365 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 )
3367 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3370 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 )
3372 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3375 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 )
3377 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3380 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)
3382 if (ShapingData[psa->eScript].charGlyphPropProc)
3383 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3384 else
3385 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3388 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3390 if (ShapingData[psa->eScript].contextProc)
3391 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3394 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)
3396 int i;
3397 INT dirL;
3399 if (!rpRangeProperties)
3400 return;
3402 if (!psc->GSUB_Table)
3403 psc->GSUB_Table = load_gsub_table(hdc);
3405 if (!psc->GSUB_Table)
3406 return;
3408 if (!psa->fLogicalOrder && psa->fRTL)
3409 dirL = -1;
3410 else
3411 dirL = 1;
3413 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3415 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3416 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3420 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3422 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3423 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3425 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3428 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3430 const GSUB_Feature *feature;
3431 int i;
3433 if (!ShapingData[psa->eScript].requiredFeatures)
3434 return S_OK;
3436 if (!psc->GSUB_Table)
3437 psc->GSUB_Table = load_gsub_table(hdc);
3439 /* we need to have at least one of the required features */
3440 i = 0;
3441 while (ShapingData[psa->eScript].requiredFeatures[i])
3443 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3444 if (feature)
3445 return S_OK;
3446 i++;
3449 return USP_E_SCRIPT_NOT_IN_FONT;