usp10: Some Indic scripts, Sinhala, want GDEF to set glyph properties.
[wine/multimedia.git] / dlls / usp10 / shape.c
blob7a3df27347ad1b798ce1148f5b85fe5c973ccfb5
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;
1362 int top_logclust = 0;
1364 if (changeCount > 0)
1366 if (write_dir > 0)
1367 target_glyph = nextIndex - changeCount;
1368 else
1369 target_glyph = nextIndex + (changeCount + 1);
1372 seeking_glyph = target_glyph;
1373 for (i = 0; i < chars; i++)
1374 if (pwLogClust[i] > top_logclust)
1375 top_logclust = pwLogClust[i];
1377 do {
1378 if (write_dir > 0)
1379 for (i = 0; i < chars; i++)
1381 if (pwLogClust[i] == seeking_glyph)
1383 target_index = i;
1384 break;
1387 else
1388 for (i = chars - 1; i >= 0; i--)
1390 if (pwLogClust[i] == seeking_glyph)
1392 target_index = i;
1393 break;
1396 if (target_index == -1)
1397 seeking_glyph ++;
1399 while (target_index == -1 && seeking_glyph <= top_logclust);
1401 if (target_index == -1)
1403 ERR("Unable to find target glyph\n");
1404 return;
1407 if (changeCount < 0)
1409 /* merge glyphs */
1410 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1412 if (pwLogClust[i] == target_glyph)
1413 continue;
1414 if(pwLogClust[i] == replacing_glyph)
1415 pwLogClust[i] = target_glyph;
1416 else
1418 changed--;
1419 if (changed >= changeCount)
1421 replacing_glyph = pwLogClust[i];
1422 pwLogClust[i] = target_glyph;
1424 else
1425 break;
1429 /* renumber trailing indexes*/
1430 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1432 if (pwLogClust[i] != target_glyph)
1433 pwLogClust[i] += changeCount;
1436 else
1438 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1439 pwLogClust[i] += changeCount;
1444 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 )
1446 if (psc->GSUB_Table)
1448 const GSUB_Feature *feature;
1449 const GSUB_LookupList *lookup;
1450 const GSUB_Header *header = psc->GSUB_Table;
1451 int lookup_index, lookup_count;
1453 feature = load_GSUB_feature(hdc, psa, psc, feat);
1454 if (!feature)
1455 return GSUB_E_NOFEATURE;
1457 TRACE("applying feature %s\n",debugstr_an(feat,4));
1458 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1459 lookup_count = GET_BE_WORD(feature->LookupCount);
1460 TRACE("%i lookups\n", lookup_count);
1461 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1463 int i;
1465 if (write_dir > 0)
1466 i = 0;
1467 else
1468 i = *pcGlyphs-1;
1469 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1470 while(i < *pcGlyphs && i >= 0)
1472 INT nextIndex;
1473 INT prevCount = *pcGlyphs;
1475 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1476 if (*pcGlyphs != prevCount)
1478 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1479 i = nextIndex;
1481 else
1482 i+=write_dir;
1485 return *pcGlyphs;
1487 return GSUB_E_NOFEATURE;
1490 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1492 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1495 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1497 if (i + delta < 0)
1498 return 0;
1499 if ( i+ delta >= cchLen)
1500 return 0;
1502 i += delta;
1504 return chars[i];
1507 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1509 if (i + delta < 0)
1511 if (psa->fLinkBefore)
1512 return jtR;
1513 else
1514 return jtU;
1516 if ( i+ delta >= cchLen)
1518 if (psa->fLinkAfter)
1519 return jtL;
1520 else
1521 return jtU;
1524 i += delta;
1526 if (context_type[i] == jtT)
1527 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1528 else
1529 return context_type[i];
1532 static inline BOOL right_join_causing(CHAR joining_type)
1534 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1537 static inline BOOL left_join_causing(CHAR joining_type)
1539 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1542 static inline BOOL word_break_causing(WCHAR chr)
1544 /* we are working within a string of characters already guareented to
1545 be within one script, Syriac, so we do not worry about any character
1546 other than the space character outside of that range */
1547 return (chr == 0 || chr == 0x20 );
1551 * ContextualShape_Arabic
1553 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1555 CHAR *context_type;
1556 INT *context_shape;
1557 INT dirR, dirL;
1558 int i;
1560 if (*pcGlyphs != cChars)
1562 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1563 return;
1566 if (!psa->fLogicalOrder && psa->fRTL)
1568 dirR = 1;
1569 dirL = -1;
1571 else
1573 dirR = -1;
1574 dirL = 1;
1577 if (!psc->GSUB_Table)
1578 psc->GSUB_Table = load_gsub_table(hdc);
1580 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1581 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1583 for (i = 0; i < cChars; i++)
1584 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1586 for (i = 0; i < cChars; i++)
1588 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1589 context_shape[i] = Xr;
1590 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1591 context_shape[i] = Xl;
1592 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)))
1593 context_shape[i] = Xm;
1594 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1595 context_shape[i] = Xr;
1596 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1597 context_shape[i] = Xl;
1598 else
1599 context_shape[i] = Xn;
1602 /* Contextual Shaping */
1603 i = 0;
1604 while(i < *pcGlyphs)
1606 BOOL shaped = FALSE;
1608 if (psc->GSUB_Table)
1610 INT nextIndex;
1611 INT prevCount = *pcGlyphs;
1612 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1613 if (nextIndex > GSUB_E_NOGLYPH)
1615 i = nextIndex;
1616 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1618 shaped = (nextIndex > GSUB_E_NOGLYPH);
1621 if (!shaped)
1623 if (context_shape[i] == Xn)
1625 WORD newGlyph = pwOutGlyphs[i];
1626 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1628 /* fall back to presentation form B */
1629 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1630 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1631 pwOutGlyphs[i] = newGlyph;
1634 i++;
1638 HeapFree(GetProcessHeap(),0,context_shape);
1639 HeapFree(GetProcessHeap(),0,context_type);
1643 * ContextualShape_Syriac
1646 #define ALAPH 0x710
1647 #define DALATH 0x715
1648 #define RISH 0x72A
1650 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1652 CHAR *context_type;
1653 INT *context_shape;
1654 INT dirR, dirL;
1655 int i;
1657 if (*pcGlyphs != cChars)
1659 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1660 return;
1663 if (!psa->fLogicalOrder && psa->fRTL)
1665 dirR = 1;
1666 dirL = -1;
1668 else
1670 dirR = -1;
1671 dirL = 1;
1674 if (!psc->GSUB_Table)
1675 psc->GSUB_Table = load_gsub_table(hdc);
1677 if (!psc->GSUB_Table)
1678 return;
1680 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1681 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1683 for (i = 0; i < cChars; i++)
1684 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1686 for (i = 0; i < cChars; i++)
1688 if (pwcChars[i] == ALAPH)
1690 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1692 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1693 context_shape[i] = Afj;
1694 else if ( rchar != DALATH && rchar != RISH &&
1695 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1696 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1697 context_shape[i] = Afn;
1698 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1699 context_shape[i] = Afx;
1700 else
1701 context_shape[i] = Xn;
1703 else if (context_type[i] == jtR &&
1704 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1705 context_shape[i] = Xr;
1706 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1707 context_shape[i] = Xl;
1708 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)))
1709 context_shape[i] = Xm;
1710 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1711 context_shape[i] = Xr;
1712 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1713 context_shape[i] = Xl;
1714 else
1715 context_shape[i] = Xn;
1718 /* Contextual Shaping */
1719 i = 0;
1720 while(i < *pcGlyphs)
1722 INT nextIndex;
1723 INT prevCount = *pcGlyphs;
1724 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1725 if (nextIndex > GSUB_E_NOGLYPH)
1727 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1728 i = nextIndex;
1730 else
1731 i++;
1734 HeapFree(GetProcessHeap(),0,context_shape);
1735 HeapFree(GetProcessHeap(),0,context_type);
1739 * ContextualShape_Phags_pa
1742 #define phags_pa_CANDRABINDU 0xA873
1743 #define phags_pa_START 0xA840
1744 #define phags_pa_END 0xA87F
1746 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1748 INT *context_shape;
1749 INT dirR, dirL;
1750 int i;
1752 if (*pcGlyphs != cChars)
1754 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1755 return;
1758 if (!psa->fLogicalOrder && psa->fRTL)
1760 dirR = 1;
1761 dirL = -1;
1763 else
1765 dirR = -1;
1766 dirL = 1;
1769 if (!psc->GSUB_Table)
1770 psc->GSUB_Table = load_gsub_table(hdc);
1772 if (!psc->GSUB_Table)
1773 return;
1775 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1777 for (i = 0; i < cChars; i++)
1779 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1781 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1782 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1783 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1784 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1786 if (jrchar && jlchar)
1787 context_shape[i] = Xm;
1788 else if (jrchar)
1789 context_shape[i] = Xr;
1790 else if (jlchar)
1791 context_shape[i] = Xl;
1792 else
1793 context_shape[i] = Xn;
1795 else
1796 context_shape[i] = -1;
1799 /* Contextual Shaping */
1800 i = 0;
1801 while(i < *pcGlyphs)
1803 if (context_shape[i] >= 0)
1805 INT nextIndex;
1806 INT prevCount = *pcGlyphs;
1807 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1808 if (nextIndex > GSUB_E_NOGLYPH)
1810 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1811 i = nextIndex;
1813 else
1814 i++;
1816 else
1817 i++;
1820 HeapFree(GetProcessHeap(),0,context_shape);
1823 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1825 int i;
1827 /* Replace */
1828 pwOutChars[cWalk] = replacements[0];
1829 cWalk=cWalk+1;
1831 /* Insert */
1832 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1834 int j;
1835 for (j = *pcChars; j > cWalk; j--)
1836 pwOutChars[j] = pwOutChars[j-1];
1837 *pcChars= *pcChars+1;
1838 pwOutChars[cWalk] = replacements[i];
1839 cWalk = cWalk+1;
1843 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1845 int i;
1846 int cWalk;
1848 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1850 for (i = 0; vowels[i].base != 0x0; i++)
1852 if (pwOutChars[cWalk] == vowels[i].base)
1854 int o = 0;
1855 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1856 if (vowels[i].parts[1]) { cWalk++; o++; }
1857 if (vowels[i].parts[2]) { cWalk++; o++; }
1858 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
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, cChars);
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, cChars);
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 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2629 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2630 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2631 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2632 {{0x0000,0x0000,0x0000}, 0x0000}};
2634 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2636 int cCount = cChars;
2637 WCHAR *input;
2638 IndicSyllable *syllables = NULL;
2639 int syllable_count = 0;
2640 BOOL modern = get_GSUB_Indic2(psa, psc);
2642 if (*pcGlyphs != cChars)
2644 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2645 return;
2648 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2649 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2651 /* Step 1: Compose Consonents */
2652 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2653 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2655 /* Step 2: Reorder within Syllables */
2656 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2657 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2658 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2659 *pcGlyphs = cCount;
2661 /* Step 3: Base Form application to syllables */
2662 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2664 HeapFree(GetProcessHeap(),0,input);
2665 HeapFree(GetProcessHeap(),0,syllables);
2668 static int gujarati_lex(WCHAR c)
2670 switch (c)
2672 case 0x0AB0: return lex_Ra;
2673 default:
2674 return unicode_lex(c);
2678 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2680 int cCount = cChars;
2681 WCHAR *input;
2682 IndicSyllable *syllables = NULL;
2683 int syllable_count = 0;
2684 BOOL modern = get_GSUB_Indic2(psa, psc);
2686 if (*pcGlyphs != cChars)
2688 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2689 return;
2692 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2693 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2695 /* Step 1: Reorder within Syllables */
2696 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2697 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2698 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2699 *pcGlyphs = cCount;
2701 /* Step 2: Base Form application to syllables */
2702 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2704 HeapFree(GetProcessHeap(),0,input);
2705 HeapFree(GetProcessHeap(),0,syllables);
2708 static int oriya_lex(WCHAR c)
2710 switch (c)
2712 case 0x0B30: return lex_Ra;
2713 default:
2714 return unicode_lex(c);
2718 static const VowelComponents Oriya_vowels[] = {
2719 {0x0B48, {0x0B47,0x0B56,0x0000}},
2720 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2721 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2722 {0x0000, {0x0000,0x0000,0x0000}}};
2724 static const ConsonantComponents Oriya_consonants[] = {
2725 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2726 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2727 {{0x0000,0x0000,0x0000}, 0x0000}};
2729 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2731 int cCount = cChars;
2732 WCHAR *input;
2733 IndicSyllable *syllables = NULL;
2734 int syllable_count = 0;
2735 BOOL modern = get_GSUB_Indic2(psa, psc);
2737 if (*pcGlyphs != cChars)
2739 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2740 return;
2743 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2744 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2746 /* Step 1: Decompose Vowels and Compose Consonents */
2747 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2748 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2749 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2751 /* Step 2: Reorder within Syllables */
2752 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2753 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2754 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2755 *pcGlyphs = cCount;
2757 /* Step 3: Base Form application to syllables */
2758 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2760 HeapFree(GetProcessHeap(),0,input);
2761 HeapFree(GetProcessHeap(),0,syllables);
2764 static int tamil_lex(WCHAR c)
2766 return unicode_lex(c);
2769 static const VowelComponents Tamil_vowels[] = {
2770 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2771 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2772 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2773 {0x0000, {0x0000,0x0000,0x0000}}};
2775 static const ConsonantComponents Tamil_consonants[] = {
2776 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2777 {{0x0000,0x0000,0x0000}, 0x0000}};
2779 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2781 int cCount = cChars;
2782 WCHAR *input;
2783 IndicSyllable *syllables = NULL;
2784 int syllable_count = 0;
2785 BOOL modern = get_GSUB_Indic2(psa, psc);
2787 if (*pcGlyphs != cChars)
2789 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2790 return;
2793 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2794 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2796 /* Step 1: Decompose Vowels and Compose Consonents */
2797 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2798 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2799 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2801 /* Step 2: Reorder within Syllables */
2802 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2803 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2804 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2805 *pcGlyphs = cCount;
2807 /* Step 3: Base Form application to syllables */
2808 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2810 HeapFree(GetProcessHeap(),0,input);
2811 HeapFree(GetProcessHeap(),0,syllables);
2814 static int telugu_lex(WCHAR c)
2816 switch (c)
2818 case 0x0C43:
2819 case 0x0C44: return lex_Modifier;
2820 default:
2821 return unicode_lex(c);
2825 static const VowelComponents Telugu_vowels[] = {
2826 {0x0C48, {0x0C46,0x0C56,0x0000}},
2827 {0x0000, {0x0000,0x0000,0x0000}}};
2829 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2831 int cCount = cChars;
2832 WCHAR *input;
2833 IndicSyllable *syllables = NULL;
2834 int syllable_count = 0;
2835 BOOL modern = get_GSUB_Indic2(psa, psc);
2837 if (*pcGlyphs != cChars)
2839 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2840 return;
2843 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2844 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2846 /* Step 1: Decompose Vowels */
2847 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2848 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2850 /* Step 2: Reorder within Syllables */
2851 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2852 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2853 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2854 *pcGlyphs = cCount;
2856 /* Step 3: Base Form application to syllables */
2857 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2859 HeapFree(GetProcessHeap(),0,input);
2860 HeapFree(GetProcessHeap(),0,syllables);
2863 static int kannada_lex(WCHAR c)
2865 switch (c)
2867 case 0x0CB0: return lex_Ra;
2868 default:
2869 return unicode_lex(c);
2873 static const VowelComponents Kannada_vowels[] = {
2874 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2875 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2876 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2877 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2878 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2879 {0x0000, {0x0000,0x0000,0x0000}}};
2881 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2883 int cCount = cChars;
2884 WCHAR *input;
2885 IndicSyllable *syllables = NULL;
2886 int syllable_count = 0;
2887 BOOL modern = get_GSUB_Indic2(psa, psc);
2889 if (*pcGlyphs != cChars)
2891 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2892 return;
2895 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2896 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2898 /* Step 1: Decompose Vowels */
2899 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2900 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2902 /* Step 2: Reorder within Syllables */
2903 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2904 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2905 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2906 *pcGlyphs = cCount;
2908 /* Step 3: Base Form application to syllables */
2909 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2911 HeapFree(GetProcessHeap(),0,input);
2912 HeapFree(GetProcessHeap(),0,syllables);
2915 static int malayalam_lex(WCHAR c)
2917 return unicode_lex(c);
2920 static const VowelComponents Malayalam_vowels[] = {
2921 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2922 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2923 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2924 {0x0000, {0x0000,0x0000,0x0000}}};
2926 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2928 int cCount = cChars;
2929 WCHAR *input;
2930 IndicSyllable *syllables = NULL;
2931 int syllable_count = 0;
2932 BOOL modern = get_GSUB_Indic2(psa, psc);
2934 if (*pcGlyphs != cChars)
2936 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2937 return;
2940 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2941 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2943 /* Step 1: Decompose Vowels */
2944 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2945 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2947 /* Step 2: Reorder within Syllables */
2948 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2949 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2950 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2951 *pcGlyphs = cCount;
2953 /* Step 3: Base Form application to syllables */
2954 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2956 HeapFree(GetProcessHeap(),0,input);
2957 HeapFree(GetProcessHeap(),0,syllables);
2960 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)
2962 int i,k;
2964 for (i = 0; i < cGlyphs; i++)
2966 int char_index[20];
2967 int char_count = 0;
2969 for (k = 0; k < cChars; k++)
2971 if (pwLogClust[k] == i)
2973 char_index[char_count] = k;
2974 char_count++;
2978 if (char_count == 0)
2979 continue;
2981 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2983 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2984 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2986 else
2987 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2990 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2991 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2994 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 )
2996 int i,k;
2997 int initGlyph, finaGlyph;
2998 INT dirR, dirL;
2999 BYTE *spaces;
3001 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3002 memset(spaces,0,cGlyphs);
3004 if (!psa->fLogicalOrder && psa->fRTL)
3006 initGlyph = cGlyphs-1;
3007 finaGlyph = 0;
3008 dirR = 1;
3009 dirL = -1;
3011 else
3013 initGlyph = 0;
3014 finaGlyph = cGlyphs-1;
3015 dirR = -1;
3016 dirL = 1;
3019 for (i = 0; i < cGlyphs; i++)
3021 for (k = 0; k < cChars; k++)
3022 if (pwLogClust[k] == i)
3024 if (pwcChars[k] == 0x0020)
3025 spaces[i] = 1;
3029 for (i = 0; i < cGlyphs; i++)
3031 int char_index[20];
3032 int char_count = 0;
3033 BOOL isInit, isFinal;
3035 for (k = 0; k < cChars; k++)
3037 if (pwLogClust[k] == i)
3039 char_index[char_count] = k;
3040 char_count++;
3044 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3045 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3047 if (char_count == 0)
3048 continue;
3050 if (char_count == 1)
3052 if (pwcChars[char_index[0]] == 0x0020) /* space */
3054 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3055 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3057 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3058 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3059 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3061 if (!isInit && !isFinal)
3062 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3063 else if (isInit)
3064 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3065 else
3066 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3068 else if (!isInit)
3070 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3071 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3072 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3073 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3074 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3075 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3076 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3077 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3078 else
3079 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3081 else if (!isInit && !isFinal)
3082 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3083 else
3084 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3086 else if (char_count == 2)
3088 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3089 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3090 else if (!isInit)
3091 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3092 else
3093 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3095 else if (!isInit && !isFinal)
3096 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3097 else
3098 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3101 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3102 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3103 HeapFree(GetProcessHeap(),0,spaces);
3106 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 )
3108 int i,k;
3109 int finaGlyph;
3110 INT dirL;
3111 BYTE *spaces;
3113 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3114 memset(spaces,0,cGlyphs);
3116 if (!psa->fLogicalOrder && psa->fRTL)
3118 finaGlyph = 0;
3119 dirL = -1;
3121 else
3123 finaGlyph = cGlyphs-1;
3124 dirL = 1;
3127 for (i = 0; i < cGlyphs; i++)
3129 for (k = 0; k < cChars; k++)
3130 if (pwLogClust[k] == i)
3132 if (pwcChars[k] == 0x0020)
3133 spaces[i] = 1;
3137 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3139 for (i = 0; i < cGlyphs; i++)
3141 int char_index[20];
3142 int char_count = 0;
3144 for (k = 0; k < cChars; k++)
3146 if (pwLogClust[k] == i)
3148 char_index[char_count] = k;
3149 char_count++;
3153 if (char_count == 0)
3154 continue;
3156 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3158 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3159 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3161 else if (i == finaGlyph)
3162 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3163 else
3164 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3166 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3167 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3168 pGlyphProp[i].sva.fClusterStart = 0;
3171 HeapFree(GetProcessHeap(),0,spaces);
3172 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3174 /* Do not allow justification between marks and their base */
3175 for (i = 0; i < cGlyphs; i++)
3177 if (!pGlyphProp[i].sva.fClusterStart)
3178 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3182 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)
3184 int i,k;
3186 for (i = 0; i < cGlyphs; i++)
3188 int char_index[20];
3189 int char_count = 0;
3191 for (k = 0; k < cChars; k++)
3193 if (pwLogClust[k] == i)
3195 char_index[char_count] = k;
3196 char_count++;
3200 if (char_count == 0)
3201 continue;
3203 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3205 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3206 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3208 else
3209 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3211 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3212 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3215 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)
3217 int i,k;
3219 for (i = 0; i < cGlyphs; i++)
3221 int char_index[20];
3222 int char_count = 0;
3224 for (k = 0; k < cChars; k++)
3226 if (pwLogClust[k] == i)
3228 char_index[char_count] = k;
3229 char_count++;
3233 if (char_count == 0)
3234 continue;
3236 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3238 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3239 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3241 else
3242 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3244 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3245 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3247 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3248 for (i = 0; i < cGlyphs; i++)
3250 if (!pGlyphProp[i].sva.fClusterStart)
3252 pGlyphProp[i].sva.fDiacritic = 0;
3253 pGlyphProp[i].sva.fZeroWidth = 0;
3258 static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables, BOOL override_gsub)
3260 int i,k;
3262 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3263 for (i = 0; i < cGlyphs; i++)
3265 int char_index[20];
3266 int char_count = 0;
3268 for (k = 0; k < cChars; k++)
3270 if (pwLogClust[k] == i)
3272 char_index[char_count] = k;
3273 char_count++;
3277 if (override_gsub)
3279 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3280 pGlyphProp[i].sva.fDiacritic = FALSE;
3281 pGlyphProp[i].sva.fZeroWidth = FALSE;
3284 if (char_count == 0)
3285 continue;
3287 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3289 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3290 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3292 else
3293 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3295 pGlyphProp[i].sva.fClusterStart = 0;
3296 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3297 switch (lexical(pwcChars[char_index[k]]))
3299 case lex_Matra_pre:
3300 case lex_Matra_post:
3301 case lex_Matra_above:
3302 case lex_Matra_below:
3303 case lex_Modifier:
3304 case lex_Halant:
3305 break;
3306 case lex_ZWJ:
3307 case lex_ZWNJ:
3308 /* check for dangling joiners */
3309 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3310 pGlyphProp[i].sva.fClusterStart = 1;
3311 else
3312 k = char_count;
3313 break;
3314 default:
3315 pGlyphProp[i].sva.fClusterStart = 1;
3316 break;
3320 if (use_syllables)
3322 IndicSyllable *syllables = NULL;
3323 int syllable_count = 0;
3324 BOOL modern = get_GSUB_Indic2(psa, psc);
3326 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3328 for (i = 0; i < syllable_count; i++)
3330 int j;
3331 WORD g = pwLogClust[syllables[i].start];
3332 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3334 if (pwLogClust[j] != g)
3336 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3337 pwLogClust[j] = g;
3342 HeapFree(GetProcessHeap(), 0, syllables);
3345 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3348 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 )
3350 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3353 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 )
3355 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3358 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 )
3360 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3363 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 )
3365 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3368 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 )
3370 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3373 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 )
3375 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3378 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 )
3380 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3383 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 )
3385 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3388 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 )
3390 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3393 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 )
3395 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3398 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)
3400 if (ShapingData[psa->eScript].charGlyphPropProc)
3401 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3402 else
3403 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3406 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3408 if (!psc->GSUB_Table)
3409 psc->GSUB_Table = load_gsub_table(hdc);
3411 if (ShapingData[psa->eScript].contextProc)
3412 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3415 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)
3417 int i;
3418 INT dirL;
3420 if (!rpRangeProperties)
3421 return;
3423 if (!psc->GSUB_Table)
3424 psc->GSUB_Table = load_gsub_table(hdc);
3426 if (!psc->GSUB_Table)
3427 return;
3429 if (!psa->fLogicalOrder && psa->fRTL)
3430 dirL = -1;
3431 else
3432 dirL = 1;
3434 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3436 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3437 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3441 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3443 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3444 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3446 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3449 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3451 const GSUB_Feature *feature;
3452 int i;
3454 if (!ShapingData[psa->eScript].requiredFeatures)
3455 return S_OK;
3457 if (!psc->GSUB_Table)
3458 psc->GSUB_Table = load_gsub_table(hdc);
3460 /* we need to have at least one of the required features */
3461 i = 0;
3462 while (ShapingData[psa->eScript].requiredFeatures[i])
3464 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3465 if (feature)
3466 return S_OK;
3467 i++;
3470 return USP_E_SCRIPT_NOT_IN_FONT;