gdi32: Always use biClrUsed for the number of colors of internal BITMAPINFO structures.
[wine/multimedia.git] / dlls / usp10 / shape.c
blob675765ae9680c96fcc9c60c74f6040be49662d95
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 OPENTYPE_FEATURE_RECORD myanmar_features[] =
457 { MS_MAKE_TAG('l','i','g','a'), 1},
458 { MS_MAKE_TAG('c','l','i','g'), 1},
461 static const char* required_bengali_features[] =
463 "nukt",
464 "akhn",
465 "rphf",
466 "blwf",
467 "half",
468 "vatu",
469 "pstf",
470 "init",
471 "abvs",
472 "blws",
473 "psts",
474 "haln",
475 NULL
478 static const char* required_gurmukhi_features[] =
480 "nukt",
481 "akhn",
482 "rphf",
483 "blwf",
484 "half",
485 "pstf",
486 "vatu",
487 "cjct",
488 "pres",
489 "abvs",
490 "blws",
491 "psts",
492 "haln",
493 "calt",
494 NULL
497 static const char* required_oriya_features[] =
499 "nukt",
500 "akhn",
501 "rphf",
502 "blwf",
503 "pstf",
504 "cjct",
505 "pres",
506 "abvs",
507 "blws",
508 "psts",
509 "haln",
510 "calt",
511 NULL
514 static const char* required_tamil_features[] =
516 "nukt",
517 "akhn",
518 "rphf",
519 "pref",
520 "half",
521 "pres",
522 "abvs",
523 "blws",
524 "psts",
525 "haln",
526 "calt",
527 NULL
530 static const char* required_telugu_features[] =
532 "nukt",
533 "akhn",
534 "rphf",
535 "pref",
536 "half",
537 "pstf",
538 "cjct",
539 "pres",
540 "abvs",
541 "blws",
542 "psts",
543 "haln",
544 "calt",
545 NULL
548 typedef struct ScriptShapeDataTag {
549 TEXTRANGE_PROPERTIES defaultTextRange;
550 const char** requiredFeatures;
551 CHAR otTag[5];
552 CHAR newOtTag[5];
553 ContextualShapingProc contextProc;
554 ShapeCharGlyphPropProc charGlyphPropProc;
555 } ScriptShapeData;
557 /* in order of scripts */
558 static const ScriptShapeData ShapingData[] =
560 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
561 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
562 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
563 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
564 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
565 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
566 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
567 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
568 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
569 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
570 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
571 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
572 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
573 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
574 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
575 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
576 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
577 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
578 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
579 {{ phags_features, 3}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
580 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
581 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
582 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
583 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
584 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
585 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
586 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
587 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
588 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
589 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
590 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
591 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
592 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
593 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
594 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
595 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
596 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
597 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
598 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
599 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
600 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
601 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
602 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
603 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
604 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
605 {{ latin_features, 2}, NULL, "latn" , "", NULL, NULL},
606 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
607 {{ myanmar_features, 2}, NULL, "mymr", "", NULL, NULL},
608 {{ myanmar_features, 2}, NULL, "mymr", "", NULL, NULL},
611 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
613 const GSUB_CoverageFormat1* cf1;
615 cf1 = table;
617 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
619 int count = GET_BE_WORD(cf1->GlyphCount);
620 int i;
621 TRACE("Coverage Format 1, %i glyphs\n",count);
622 for (i = 0; i < count; i++)
623 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
624 return i;
625 return -1;
627 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
629 const GSUB_CoverageFormat2* cf2;
630 int i;
631 int count;
632 cf2 = (const GSUB_CoverageFormat2*)cf1;
634 count = GET_BE_WORD(cf2->RangeCount);
635 TRACE("Coverage Format 2, %i ranges\n",count);
636 for (i = 0; i < count; i++)
638 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
639 return -1;
640 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
641 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
643 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
644 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
647 return -1;
649 else
650 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
652 return -1;
655 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
657 const GSUB_ScriptList *script;
658 const GSUB_Script *deflt = NULL;
659 int i;
660 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
662 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
663 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
665 const GSUB_Script *scr;
666 int offset;
668 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
669 scr = (const GSUB_Script*)((const BYTE*)script + offset);
671 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
672 return scr;
673 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
674 deflt = scr;
676 return deflt;
679 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
681 int i;
682 int offset;
683 const GSUB_LangSys *Lang;
685 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
687 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
689 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
690 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
692 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
693 return Lang;
695 offset = GET_BE_WORD(script->DefaultLangSys);
696 if (offset)
698 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
699 return Lang;
701 return NULL;
704 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
706 int i;
707 const GSUB_FeatureList *feature;
708 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
710 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
711 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
713 int index = GET_BE_WORD(lang->FeatureIndex[i]);
714 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
716 const GSUB_Feature *feat;
717 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
718 return feat;
721 return NULL;
724 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
726 int j;
727 TRACE("Single Substitution Subtable\n");
729 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
731 int offset;
732 const GSUB_SingleSubstFormat1 *ssf1;
733 offset = GET_BE_WORD(look->SubTable[j]);
734 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
735 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
737 int offset = GET_BE_WORD(ssf1->Coverage);
738 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
739 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
741 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
742 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
743 TRACE(" 0x%x\n",glyphs[glyph_index]);
744 return glyph_index + write_dir;
747 else
749 const GSUB_SingleSubstFormat2 *ssf2;
750 INT index;
751 INT offset;
753 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
754 offset = GET_BE_WORD(ssf1->Coverage);
755 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
756 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
757 TRACE(" Coverage index %i\n",index);
758 if (index != -1)
760 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
761 return GSUB_E_NOGLYPH;
763 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
764 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
765 TRACE("0x%x\n",glyphs[glyph_index]);
766 return glyph_index + write_dir;
770 return GSUB_E_NOGLYPH;
773 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
775 int j;
776 TRACE("Multiple Substitution Subtable\n");
778 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
780 int offset, index;
781 const GSUB_MultipleSubstFormat1 *msf1;
782 offset = GET_BE_WORD(look->SubTable[j]);
783 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
785 offset = GET_BE_WORD(msf1->Coverage);
786 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
787 if (index != -1)
789 const GSUB_Sequence *seq;
790 int sub_count;
791 int j;
792 offset = GET_BE_WORD(msf1->Sequence[index]);
793 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
794 sub_count = GET_BE_WORD(seq->GlyphCount);
795 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
797 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
798 glyphs[j] =glyphs[j-(sub_count-1)];
800 for (j = 0; j < sub_count; j++)
801 if (write_dir < 0)
802 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
803 else
804 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
806 *glyph_count = *glyph_count + (sub_count - 1);
808 if (TRACE_ON(uniscribe))
810 for (j = 0; j < sub_count; j++)
811 TRACE(" 0x%x",glyphs[glyph_index+j]);
812 TRACE("\n");
815 return glyph_index + (sub_count * write_dir);
818 return GSUB_E_NOGLYPH;
821 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
823 int j;
824 TRACE("Alternate Substitution Subtable\n");
826 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
828 int offset;
829 const GSUB_AlternateSubstFormat1 *asf1;
830 INT index;
832 offset = GET_BE_WORD(look->SubTable[j]);
833 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
834 offset = GET_BE_WORD(asf1->Coverage);
836 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
837 if (index != -1)
839 const GSUB_AlternateSet *as;
840 offset = GET_BE_WORD(asf1->AlternateSet[index]);
841 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
842 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
843 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
844 return GSUB_E_NOGLYPH;
846 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
847 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
848 TRACE(" 0x%x\n",glyphs[glyph_index]);
849 return glyph_index + write_dir;
852 return GSUB_E_NOGLYPH;
855 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
857 int j;
859 TRACE("Ligature Substitution Subtable\n");
860 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
862 const GSUB_LigatureSubstFormat1 *lsf1;
863 int offset,index;
865 offset = GET_BE_WORD(look->SubTable[j]);
866 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
867 offset = GET_BE_WORD(lsf1->Coverage);
868 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
869 TRACE(" Coverage index %i\n",index);
870 if (index != -1)
872 const GSUB_LigatureSet *ls;
873 int k, count;
875 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
876 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
877 count = GET_BE_WORD(ls->LigatureCount);
878 TRACE(" LigatureSet has %i members\n",count);
879 for (k = 0; k < count; k++)
881 const GSUB_Ligature *lig;
882 int CompCount,l,CompIndex;
884 offset = GET_BE_WORD(ls->Ligature[k]);
885 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
886 CompCount = GET_BE_WORD(lig->CompCount) - 1;
887 CompIndex = glyph_index+write_dir;
888 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
890 int CompGlyph;
891 CompGlyph = GET_BE_WORD(lig->Component[l]);
892 if (CompGlyph != glyphs[CompIndex])
893 break;
894 CompIndex += write_dir;
896 if (l == CompCount)
898 int replaceIdx = glyph_index;
899 if (write_dir < 0)
900 replaceIdx = glyph_index - CompCount;
902 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
903 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
904 TRACE("0x%x\n",glyphs[replaceIdx]);
905 if (CompCount > 0)
907 int j;
908 for (j = replaceIdx + 1; j < *glyph_count; j++)
909 glyphs[j] =glyphs[j+CompCount];
910 *glyph_count = *glyph_count - CompCount;
912 return replaceIdx + write_dir;
917 return GSUB_E_NOGLYPH;
920 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
922 int j;
923 BOOL done = FALSE;
925 TRACE("Chaining Contextual Substitution Subtable\n");
926 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
928 const GSUB_ChainContextSubstFormat1 *ccsf1;
929 int offset;
930 int dirLookahead = write_dir;
931 int dirBacktrack = -1 * write_dir;
933 offset = GET_BE_WORD(look->SubTable[j]);
934 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
935 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
937 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
938 continue;
940 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
942 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
943 continue;
945 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
947 int k;
948 int indexGlyphs;
949 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
950 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
951 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
952 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
953 int newIndex = glyph_index;
955 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
957 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
959 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
961 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
962 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
963 break;
965 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
966 continue;
967 TRACE("Matched Backtrack\n");
969 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
971 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
972 for (k = 0; k < indexGlyphs; k++)
974 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
975 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
976 break;
978 if (k != indexGlyphs)
979 continue;
980 TRACE("Matched IndexGlyphs\n");
982 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
984 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
986 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
987 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
988 break;
990 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
991 continue;
992 TRACE("Matched LookAhead\n");
994 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
996 if (GET_BE_WORD(ccsf3_4->SubstCount))
998 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
1000 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
1001 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
1003 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1004 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
1005 if (newIndex == -1)
1007 ERR("Chain failed to generate a glyph\n");
1008 continue;
1011 return newIndex;
1013 else return GSUB_E_NOGLYPH;
1016 return -1;
1019 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1021 int offset;
1022 const GSUB_LookupTable *look;
1024 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1025 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1026 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1027 switch(GET_BE_WORD(look->LookupType))
1029 case 1:
1030 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1031 case 2:
1032 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1033 case 3:
1034 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1035 case 4:
1036 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1037 case 6:
1038 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1039 default:
1040 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1042 return GSUB_E_NOGLYPH;
1045 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)
1047 int i;
1048 int out_index = GSUB_E_NOGLYPH;
1049 const GSUB_LookupList *lookup;
1051 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1053 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1054 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1056 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1057 if (out_index != GSUB_E_NOGLYPH)
1058 break;
1060 if (out_index == GSUB_E_NOGLYPH)
1061 TRACE("lookups found no glyphs\n");
1062 else
1064 int out2;
1065 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1066 if (out2!=GSUB_E_NOGLYPH)
1067 out_index = out2;
1069 return out_index;
1072 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1074 UINT charset;
1076 if (psc->userScript != 0)
1078 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1079 return ShapingData[psa->eScript].newOtTag;
1080 else
1081 return (char*)&psc->userScript;
1084 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1085 return ShapingData[psa->eScript].newOtTag;
1087 if (ShapingData[psa->eScript].otTag[0] != 0)
1088 return ShapingData[psa->eScript].otTag;
1091 * fall back to the font charset
1093 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1094 switch (charset)
1096 case ANSI_CHARSET: return "latn";
1097 case BALTIC_CHARSET: return "latn"; /* ?? */
1098 case CHINESEBIG5_CHARSET: return "hani";
1099 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1100 case GB2312_CHARSET: return "hani";
1101 case GREEK_CHARSET: return "grek";
1102 case HANGUL_CHARSET: return "hang";
1103 case RUSSIAN_CHARSET: return "cyrl";
1104 case SHIFTJIS_CHARSET: return "kana";
1105 case TURKISH_CHARSET: return "latn"; /* ?? */
1106 case VIETNAMESE_CHARSET: return "latn";
1107 case JOHAB_CHARSET: return "latn"; /* ?? */
1108 case ARABIC_CHARSET: return "arab";
1109 case HEBREW_CHARSET: return "hebr";
1110 case THAI_CHARSET: return "thai";
1111 default: return "latn";
1115 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1117 const GSUB_Feature *feature;
1118 const char* script;
1119 int i;
1121 script = get_opentype_script(hdc,psa,psc,FALSE);
1123 for (i = 0; i < psc->feature_count; i++)
1125 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1126 return psc->features[i].feature;
1129 feature = NULL;
1131 if (psc->GSUB_Table)
1133 const GSUB_Script *script;
1134 const GSUB_LangSys *language;
1135 int attempt = 2;
1139 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1140 attempt--;
1141 if (script)
1143 if (psc->userLang != 0)
1144 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1145 else
1146 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1147 if (language)
1148 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1150 } while(attempt && !feature);
1152 /* try in the default (latin) table */
1153 if (!feature)
1155 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1156 if (script)
1158 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1159 if (language)
1160 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1165 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1167 psc->feature_count++;
1169 if (psc->features)
1170 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1171 else
1172 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1174 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1175 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1176 psc->features[psc->feature_count - 1].feature = feature;
1177 return feature;
1180 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)
1182 const GSUB_Feature *feature;
1184 feature = load_GSUB_feature(hdc, psa, psc, feat);
1185 if (!feature)
1186 return GSUB_E_NOFEATURE;
1188 TRACE("applying feature %s\n",feat);
1189 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1192 static VOID *load_gsub_table(HDC hdc)
1194 VOID* GSUB_Table = NULL;
1195 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1196 if (length != GDI_ERROR)
1198 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1199 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1200 TRACE("Loaded GSUB table of %i bytes\n",length);
1202 return GSUB_Table;
1205 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)
1207 WORD *glyphs;
1208 INT glyph_count = count;
1209 INT rc;
1211 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1212 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1213 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1214 if (rc > GSUB_E_NOGLYPH)
1215 rc = count - glyph_count;
1216 else
1217 rc = 0;
1219 HeapFree(GetProcessHeap(),0,glyphs);
1220 return rc;
1223 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1225 int offset;
1226 WORD class = 0;
1227 const GDEF_ClassDefFormat1 *cf1;
1229 if (!header)
1230 return 0;
1232 offset = GET_BE_WORD(header->GlyphClassDef);
1233 if (!offset)
1234 return 0;
1236 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1237 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1239 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1241 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1242 if (index < GET_BE_WORD(cf1->GlyphCount))
1243 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1246 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1248 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1249 int i, top;
1250 top = GET_BE_WORD(cf2->ClassRangeCount);
1251 for (i = 0; i < top; i++)
1253 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1254 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1256 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1257 break;
1261 else
1262 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1264 return class;
1267 static VOID *load_gdef_table(HDC hdc)
1269 VOID* GDEF_Table = NULL;
1270 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1271 if (length != GDI_ERROR)
1273 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1274 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1275 TRACE("Loaded GDEF table of %i bytes\n",length);
1277 return GDEF_Table;
1280 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
1282 int i;
1284 if (!psc->GDEF_Table)
1285 psc->GDEF_Table = load_gdef_table(hdc);
1287 for (i = 0; i < cGlyphs; i++)
1289 WORD class;
1290 int char_count = 0;
1291 int k;
1293 for (k = 0; k < cChars; k++)
1294 if (pwLogClust[k] == i)
1295 char_count++;
1297 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1299 switch (class)
1301 case 0:
1302 case BaseGlyph:
1303 pGlyphProp[i].sva.fClusterStart = 1;
1304 pGlyphProp[i].sva.fDiacritic = 0;
1305 pGlyphProp[i].sva.fZeroWidth = 0;
1306 break;
1307 case LigatureGlyph:
1308 pGlyphProp[i].sva.fClusterStart = 1;
1309 pGlyphProp[i].sva.fDiacritic = 0;
1310 pGlyphProp[i].sva.fZeroWidth = 0;
1311 break;
1312 case MarkGlyph:
1313 pGlyphProp[i].sva.fClusterStart = 0;
1314 pGlyphProp[i].sva.fDiacritic = 1;
1315 pGlyphProp[i].sva.fZeroWidth = 1;
1316 break;
1317 case ComponentGlyph:
1318 pGlyphProp[i].sva.fClusterStart = 0;
1319 pGlyphProp[i].sva.fDiacritic = 0;
1320 pGlyphProp[i].sva.fZeroWidth = 0;
1321 break;
1322 default:
1323 ERR("Unknown glyph class %i\n",class);
1324 pGlyphProp[i].sva.fClusterStart = 1;
1325 pGlyphProp[i].sva.fDiacritic = 0;
1326 pGlyphProp[i].sva.fZeroWidth = 0;
1329 if (char_count == 0)
1330 pGlyphProp[i].sva.fClusterStart = 0;
1334 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1336 int i;
1338 for (i = 0; i < cGlyphs; i++)
1340 if (!pGlyphProp[i].sva.fClusterStart)
1342 int j;
1343 for (j = 0; j < cChars; j++)
1345 if (pwLogClust[j] == i)
1347 int k = j;
1348 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1349 k-=1;
1350 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1351 pwLogClust[j] = pwLogClust[k];
1358 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1360 if (changeCount == 0)
1361 return;
1362 else
1364 int i;
1365 int target_glyph = nextIndex - write_dir;
1366 int seeking_glyph;
1367 int target_index = -1;
1368 int replacing_glyph = -1;
1369 int changed = 0;
1370 int top_logclust = 0;
1372 if (changeCount > 0)
1374 if (write_dir > 0)
1375 target_glyph = nextIndex - changeCount;
1376 else
1377 target_glyph = nextIndex + (changeCount + 1);
1380 seeking_glyph = target_glyph;
1381 for (i = 0; i < chars; i++)
1382 if (pwLogClust[i] > top_logclust)
1383 top_logclust = pwLogClust[i];
1385 do {
1386 if (write_dir > 0)
1387 for (i = 0; i < chars; i++)
1389 if (pwLogClust[i] == seeking_glyph)
1391 target_index = i;
1392 break;
1395 else
1396 for (i = chars - 1; i >= 0; i--)
1398 if (pwLogClust[i] == seeking_glyph)
1400 target_index = i;
1401 break;
1404 if (target_index == -1)
1405 seeking_glyph ++;
1407 while (target_index == -1 && seeking_glyph <= top_logclust);
1409 if (target_index == -1)
1411 ERR("Unable to find target glyph\n");
1412 return;
1415 if (changeCount < 0)
1417 /* merge glyphs */
1418 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1420 if (pwLogClust[i] == target_glyph)
1421 continue;
1422 if(pwLogClust[i] == replacing_glyph)
1423 pwLogClust[i] = target_glyph;
1424 else
1426 changed--;
1427 if (changed >= changeCount)
1429 replacing_glyph = pwLogClust[i];
1430 pwLogClust[i] = target_glyph;
1432 else
1433 break;
1437 /* renumber trailing indexes*/
1438 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1440 if (pwLogClust[i] != target_glyph)
1441 pwLogClust[i] += changeCount;
1444 else
1446 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1447 pwLogClust[i] += changeCount;
1452 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 )
1454 if (psc->GSUB_Table)
1456 const GSUB_Feature *feature;
1457 const GSUB_LookupList *lookup;
1458 const GSUB_Header *header = psc->GSUB_Table;
1459 int lookup_index, lookup_count;
1461 feature = load_GSUB_feature(hdc, psa, psc, feat);
1462 if (!feature)
1463 return GSUB_E_NOFEATURE;
1465 TRACE("applying feature %s\n",debugstr_an(feat,4));
1466 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1467 lookup_count = GET_BE_WORD(feature->LookupCount);
1468 TRACE("%i lookups\n", lookup_count);
1469 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1471 int i;
1473 if (write_dir > 0)
1474 i = 0;
1475 else
1476 i = *pcGlyphs-1;
1477 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1478 while(i < *pcGlyphs && i >= 0)
1480 INT nextIndex;
1481 INT prevCount = *pcGlyphs;
1483 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1484 if (*pcGlyphs != prevCount)
1486 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1487 i = nextIndex;
1489 else
1490 i+=write_dir;
1493 return *pcGlyphs;
1495 return GSUB_E_NOFEATURE;
1498 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1500 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1503 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1505 if (i + delta < 0)
1506 return 0;
1507 if ( i+ delta >= cchLen)
1508 return 0;
1510 i += delta;
1512 return chars[i];
1515 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1517 if (i + delta < 0)
1519 if (psa->fLinkBefore)
1520 return jtR;
1521 else
1522 return jtU;
1524 if ( i+ delta >= cchLen)
1526 if (psa->fLinkAfter)
1527 return jtL;
1528 else
1529 return jtU;
1532 i += delta;
1534 if (context_type[i] == jtT)
1535 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1536 else
1537 return context_type[i];
1540 static inline BOOL right_join_causing(CHAR joining_type)
1542 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1545 static inline BOOL left_join_causing(CHAR joining_type)
1547 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1550 static inline BOOL word_break_causing(WCHAR chr)
1552 /* we are working within a string of characters already guareented to
1553 be within one script, Syriac, so we do not worry about any character
1554 other than the space character outside of that range */
1555 return (chr == 0 || chr == 0x20 );
1559 * ContextualShape_Arabic
1561 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1563 CHAR *context_type;
1564 INT *context_shape;
1565 INT dirR, dirL;
1566 int i;
1568 if (*pcGlyphs != cChars)
1570 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1571 return;
1574 if (!psa->fLogicalOrder && psa->fRTL)
1576 dirR = 1;
1577 dirL = -1;
1579 else
1581 dirR = -1;
1582 dirL = 1;
1585 if (!psc->GSUB_Table)
1586 psc->GSUB_Table = load_gsub_table(hdc);
1588 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1589 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1591 for (i = 0; i < cChars; i++)
1592 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1594 for (i = 0; i < cChars; i++)
1596 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1597 context_shape[i] = Xr;
1598 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1599 context_shape[i] = Xl;
1600 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)))
1601 context_shape[i] = Xm;
1602 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1603 context_shape[i] = Xr;
1604 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1605 context_shape[i] = Xl;
1606 else
1607 context_shape[i] = Xn;
1610 /* Contextual Shaping */
1611 i = 0;
1612 while(i < *pcGlyphs)
1614 BOOL shaped = FALSE;
1616 if (psc->GSUB_Table)
1618 INT nextIndex;
1619 INT prevCount = *pcGlyphs;
1620 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1621 if (nextIndex > GSUB_E_NOGLYPH)
1623 i = nextIndex;
1624 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1626 shaped = (nextIndex > GSUB_E_NOGLYPH);
1629 if (!shaped)
1631 if (context_shape[i] == Xn)
1633 WORD newGlyph = pwOutGlyphs[i];
1634 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1636 /* fall back to presentation form B */
1637 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1638 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1639 pwOutGlyphs[i] = newGlyph;
1642 i++;
1646 HeapFree(GetProcessHeap(),0,context_shape);
1647 HeapFree(GetProcessHeap(),0,context_type);
1651 * ContextualShape_Syriac
1654 #define ALAPH 0x710
1655 #define DALATH 0x715
1656 #define RISH 0x72A
1658 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1660 CHAR *context_type;
1661 INT *context_shape;
1662 INT dirR, dirL;
1663 int i;
1665 if (*pcGlyphs != cChars)
1667 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1668 return;
1671 if (!psa->fLogicalOrder && psa->fRTL)
1673 dirR = 1;
1674 dirL = -1;
1676 else
1678 dirR = -1;
1679 dirL = 1;
1682 if (!psc->GSUB_Table)
1683 psc->GSUB_Table = load_gsub_table(hdc);
1685 if (!psc->GSUB_Table)
1686 return;
1688 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1689 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1691 for (i = 0; i < cChars; i++)
1692 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1694 for (i = 0; i < cChars; i++)
1696 if (pwcChars[i] == ALAPH)
1698 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1700 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1701 context_shape[i] = Afj;
1702 else if ( rchar != DALATH && rchar != RISH &&
1703 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1704 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1705 context_shape[i] = Afn;
1706 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1707 context_shape[i] = Afx;
1708 else
1709 context_shape[i] = Xn;
1711 else if (context_type[i] == jtR &&
1712 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1713 context_shape[i] = Xr;
1714 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1715 context_shape[i] = Xl;
1716 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)))
1717 context_shape[i] = Xm;
1718 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1719 context_shape[i] = Xr;
1720 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1721 context_shape[i] = Xl;
1722 else
1723 context_shape[i] = Xn;
1726 /* Contextual Shaping */
1727 i = 0;
1728 while(i < *pcGlyphs)
1730 INT nextIndex;
1731 INT prevCount = *pcGlyphs;
1732 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1733 if (nextIndex > GSUB_E_NOGLYPH)
1735 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1736 i = nextIndex;
1738 else
1739 i++;
1742 HeapFree(GetProcessHeap(),0,context_shape);
1743 HeapFree(GetProcessHeap(),0,context_type);
1747 * ContextualShape_Phags_pa
1750 #define phags_pa_CANDRABINDU 0xA873
1751 #define phags_pa_START 0xA840
1752 #define phags_pa_END 0xA87F
1754 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1756 INT *context_shape;
1757 INT dirR, dirL;
1758 int i;
1760 if (*pcGlyphs != cChars)
1762 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1763 return;
1766 if (!psa->fLogicalOrder && psa->fRTL)
1768 dirR = 1;
1769 dirL = -1;
1771 else
1773 dirR = -1;
1774 dirL = 1;
1777 if (!psc->GSUB_Table)
1778 psc->GSUB_Table = load_gsub_table(hdc);
1780 if (!psc->GSUB_Table)
1781 return;
1783 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1785 for (i = 0; i < cChars; i++)
1787 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1789 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1790 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1791 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1792 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1794 if (jrchar && jlchar)
1795 context_shape[i] = Xm;
1796 else if (jrchar)
1797 context_shape[i] = Xr;
1798 else if (jlchar)
1799 context_shape[i] = Xl;
1800 else
1801 context_shape[i] = Xn;
1803 else
1804 context_shape[i] = -1;
1807 /* Contextual Shaping */
1808 i = 0;
1809 while(i < *pcGlyphs)
1811 if (context_shape[i] >= 0)
1813 INT nextIndex;
1814 INT prevCount = *pcGlyphs;
1815 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1816 if (nextIndex > GSUB_E_NOGLYPH)
1818 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1819 i = nextIndex;
1821 else
1822 i++;
1824 else
1825 i++;
1828 HeapFree(GetProcessHeap(),0,context_shape);
1831 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1833 int i;
1835 /* Replace */
1836 pwOutChars[cWalk] = replacements[0];
1837 cWalk=cWalk+1;
1839 /* Insert */
1840 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1842 int j;
1843 for (j = *pcChars; j > cWalk; j--)
1844 pwOutChars[j] = pwOutChars[j-1];
1845 *pcChars= *pcChars+1;
1846 pwOutChars[cWalk] = replacements[i];
1847 cWalk = cWalk+1;
1851 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1853 int i;
1854 int cWalk;
1856 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1858 for (i = 0; vowels[i].base != 0x0; i++)
1860 if (pwOutChars[cWalk] == vowels[i].base)
1862 int o = 0;
1863 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1864 if (vowels[i].parts[1]) { cWalk++; o++; }
1865 if (vowels[i].parts[2]) { cWalk++; o++; }
1866 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1867 break;
1873 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1875 int i;
1876 int offset = 0;
1877 int cWalk;
1879 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1881 for (i = 0; consonants[i].output!= 0x0; i++)
1883 int j;
1884 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1885 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1886 break;
1888 if (consonants[i].parts[j]==0x0) /* matched all */
1890 int k;
1891 j--;
1892 pwOutChars[cWalk] = consonants[i].output;
1893 for(k = cWalk+1; k < *pcChars - j; k++)
1894 pwOutChars[k] = pwOutChars[k+j];
1895 *pcChars = *pcChars - j;
1896 for (k = j ; k > 0; k--)
1897 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1898 offset += j;
1899 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1900 pwLogClust[k]--;
1901 break;
1904 cWalk++;
1908 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1910 if (s->ralf >= 0)
1912 int j;
1913 WORD Ra = pwChar[s->start];
1914 WORD H = pwChar[s->start+1];
1916 TRACE("Doing reorder of Ra to %i\n",s->base);
1917 for (j = s->start; j < s->base-1; j++)
1918 pwChar[j] = pwChar[j+2];
1919 pwChar[s->base-1] = Ra;
1920 pwChar[s->base] = H;
1922 s->ralf = s->base-1;
1923 s->base -= 2;
1927 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1929 if (s->ralf >= 0)
1931 int j,loc;
1932 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1933 WORD Ra = pwChar[s->start];
1934 WORD H = pwChar[s->start+1];
1935 for (loc = s->end; loc > stop; loc--)
1936 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1937 break;
1939 TRACE("Doing reorder of Ra to %i\n",loc);
1940 for (j = s->start; j < loc-1; j++)
1941 pwChar[j] = pwChar[j+2];
1942 pwChar[loc-1] = Ra;
1943 pwChar[loc] = H;
1945 s->ralf = loc-1;
1946 s->base -= 2;
1947 if (s->blwf >= 0) s->blwf -= 2;
1948 if (s->pref >= 0) s->pref -= 2;
1952 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1954 if (s->ralf >= 0)
1956 int j;
1957 WORD Ra = pwChar[s->start];
1958 WORD H = pwChar[s->start+1];
1960 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1961 for (j = s->start; j < s->end-1; j++)
1962 pwChar[j] = pwChar[j+2];
1963 pwChar[s->end-1] = Ra;
1964 pwChar[s->end] = H;
1966 s->ralf = s->end-1;
1967 s->base -= 2;
1968 if (s->blwf >= 0) s->blwf -= 2;
1969 if (s->pref >= 0) s->pref -= 2;
1973 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1975 int i;
1977 /* reorder Matras */
1978 if (s->end > s->base)
1980 for (i = 1; i <= s->end-s->base; i++)
1982 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1984 int j;
1985 WCHAR c = pwChar[s->base+i];
1986 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1987 for (j = s->base+i; j > s->base; j--)
1988 pwChar[j] = pwChar[j-1];
1989 pwChar[s->base] = c;
1991 if (s->ralf >= s->base) s->ralf++;
1992 if (s->blwf >= s->base) s->blwf++;
1993 if (s->pref >= s->base) s->pref++;
1994 s->base ++;
2000 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2002 int i;
2004 /* reorder Matras */
2005 if (s->end > s->base)
2007 for (i = 1; i <= s->end-s->base; i++)
2009 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2011 int j;
2012 WCHAR c = pwChar[s->base+i];
2013 TRACE("Doing reorder of %x to %i\n",c,s->start);
2014 for (j = s->base+i; j > s->start; j--)
2015 pwChar[j] = pwChar[j-1];
2016 pwChar[s->start] = c;
2018 if (s->ralf >= 0) s->ralf++;
2019 if (s->blwf >= 0) s->blwf++;
2020 if (s->pref >= 0) s->pref++;
2021 s->base ++;
2027 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2029 if (s->blwf >= 0 && g->blwf > g->base)
2031 int j,loc;
2032 int g_offset;
2033 for (loc = s->end; loc > s->blwf; loc--)
2034 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2035 break;
2037 g_offset = (loc - s->blwf) - 1;
2039 if (loc != s->blwf)
2041 WORD blwf = glyphs[g->blwf];
2042 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2043 /* do not care about the pwChar array anymore, just the glyphs */
2044 for (j = 0; j < g_offset; j++)
2045 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2046 glyphs[g->blwf + g_offset] = blwf;
2051 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2053 int i;
2055 /* reorder previously moved Matras to correct position*/
2056 for (i = s->start; i < s->base; i++)
2058 if (lexical(pwChar[i]) == lex_Matra_pre)
2060 int j;
2061 int g_start = g->start + i - s->start;
2062 if (g_start < g->base -1 )
2064 WCHAR og = glyphs[g_start];
2065 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2066 for (j = g_start; j < g->base-1; j++)
2067 glyphs[j] = glyphs[j+1];
2068 glyphs[g->base-1] = og;
2074 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2076 if (s->pref >= 0 && g->pref > g->base)
2078 int j;
2079 WCHAR og = glyphs[g->pref];
2080 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2081 for (j = g->pref; j > g->base; j--)
2082 glyphs[j] = glyphs[j-1];
2083 glyphs[g->base] = og;
2087 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2089 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2090 if (s->start == s->base && s->base == s->end) return;
2091 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2093 Reorder_Ra_follows_base(pwChar, s, lexical);
2094 Reorder_Matra_precede_base(pwChar, s, lexical);
2097 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2099 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2100 if (s->start == s->base && s->base == s->end) return;
2101 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2103 Reorder_Ra_follows_matra(pwChar, s, lexical);
2104 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2107 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2109 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2110 if (s->start == s->base && s->base == s->end) return;
2111 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2113 Reorder_Ra_follows_base(pwChar, s, lexical);
2114 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2117 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2119 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2120 if (s->start == s->base && s->base == s->end) return;
2121 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2123 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2124 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2127 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2129 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2130 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2131 if (s->start == s->base && s->base == s->end) return;
2132 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2134 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2137 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2139 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2140 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2141 if (s->start == s->base && s->base == s->end) return;
2142 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2144 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2145 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2149 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2151 if (shift == 0)
2152 return;
2154 if (glyph_index->start > index)
2155 glyph_index->start += shift;
2156 if (glyph_index->base > index)
2157 glyph_index->base+= shift;
2158 if (glyph_index->end > index)
2159 glyph_index->end+= shift;
2160 if (glyph_index->ralf > index)
2161 glyph_index->ralf+= shift;
2162 if (glyph_index->blwf > index)
2163 glyph_index->blwf+= shift;
2164 if (glyph_index->pref > index)
2165 glyph_index->pref+= shift;
2168 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 )
2170 int index = glyph_index->start;
2172 if (!feature)
2173 return;
2175 while(index <= glyph_index->end)
2177 INT nextIndex;
2178 INT prevCount = *pcGlyphs;
2179 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2180 if (nextIndex > GSUB_E_NOGLYPH)
2182 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2183 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2184 index = nextIndex;
2186 else
2187 index++;
2191 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2193 int i = 0;
2194 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)))))
2195 i++;
2196 if (index + i <= end-1)
2197 return index + i;
2198 else
2199 return -1;
2202 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)
2204 INT index, nextIndex;
2205 INT count,g_offset;
2207 count = syllable->base - syllable->start;
2209 g_offset = 0;
2210 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2211 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2213 INT prevCount = *pcGlyphs;
2214 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2215 if (nextIndex > GSUB_E_NOGLYPH)
2217 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2218 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2219 g_offset += (*pcGlyphs - prevCount);
2222 index+=2;
2223 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2227 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)
2229 INT nextIndex;
2230 INT prevCount = *pcGlyphs;
2232 if (syllable->ralf >= 0)
2234 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2235 if (nextIndex > GSUB_E_NOGLYPH)
2237 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2238 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2243 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2245 int i = 0;
2246 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2247 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2248 is_consonant(lexical(pwChars[index+i+1])))))
2249 i++;
2250 if (index + i <= end-1)
2251 return index+i;
2252 else
2253 return -1;
2256 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)
2258 INT index, nextIndex;
2259 INT count, g_offset=0;
2260 INT ralf = syllable->ralf;
2262 count = syllable->end - syllable->base;
2264 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2266 while (index >= 0)
2268 INT prevCount = *pcGlyphs;
2269 if (ralf >=0 && ralf < index)
2271 g_offset--;
2272 ralf = -1;
2275 if (!modern)
2277 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2278 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2279 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2282 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2283 if (nextIndex > GSUB_E_NOGLYPH)
2285 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2286 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2287 g_offset += (*pcGlyphs - prevCount);
2289 else if (!modern)
2291 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2292 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2293 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2296 index+=2;
2297 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2301 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)
2303 int c;
2304 int overall_shift = 0;
2305 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2306 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2307 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2308 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2309 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2310 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2311 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2312 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2313 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2314 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2315 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2316 IndicSyllable glyph_indexs;
2318 for (c = 0; c < syllable_count; c++)
2320 int old_end;
2321 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2322 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2323 old_end = glyph_indexs.end;
2325 if (locl)
2327 TRACE("applying feature locl\n");
2328 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2330 if (nukt)
2332 TRACE("applying feature nukt\n");
2333 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2335 if (akhn)
2337 TRACE("applying feature akhn\n");
2338 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2341 if (rphf)
2342 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2343 if (rkrf)
2345 TRACE("applying feature rkrf\n");
2346 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2348 if (pref)
2349 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2350 if (blwf)
2352 if (!modern)
2353 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2355 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2358 if (half)
2359 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2360 if (pstf)
2362 TRACE("applying feature pstf\n");
2363 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2365 if (vatu)
2367 TRACE("applying feature vatu\n");
2368 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2370 if (cjct)
2372 TRACE("applying feature cjct\n");
2373 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2376 if (second_reorder)
2377 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2379 overall_shift += glyph_indexs.end - old_end;
2383 static inline int unicode_lex(WCHAR c)
2385 int type;
2387 if (!c) return lex_Generic;
2388 if (c == 0x200D) return lex_ZWJ;
2389 if (c == 0x200C) return lex_ZWNJ;
2390 if (c == 0x00A0) return lex_NBSP;
2392 type = get_table_entry( indic_syllabic_table, c );
2394 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2396 switch( type )
2398 case 0x0d07: /* Unknown */
2399 case 0x0e07: /* Unknwon */
2400 default: return lex_Generic;
2401 case 0x0001:
2402 case 0x0002:
2403 case 0x0011:
2404 case 0x0012:
2405 case 0x0013:
2406 case 0x0014: return lex_Modifier;
2407 case 0x0003:
2408 case 0x0009:
2409 case 0x000a:
2410 case 0x000b:
2411 case 0x000d:
2412 case 0x000e:
2413 case 0x000f:
2414 case 0x0010: return lex_Consonant;
2415 case 0x0004: return lex_Nukta;
2416 case 0x0005: return lex_Halant;
2417 case 0x0006:
2418 case 0x0008: return lex_Vowel;
2419 case 0x0007:
2420 case 0x0107: return lex_Matra_post;
2421 case 0x0207:
2422 case 0x0307: return lex_Matra_pre;
2423 case 0x0807:
2424 case 0x0907:
2425 case 0x0a07:
2426 case 0x0b07:
2427 case 0x0c07:
2428 case 0x0407: return lex_Composed_Vowel;
2429 case 0x0507: return lex_Matra_above;
2430 case 0x0607: return lex_Matra_below;
2431 case 0x000c: return lex_Ra;
2435 static int sinhala_lex(WCHAR c)
2437 switch (c)
2439 case 0x0DDA:
2440 case 0x0DDD:
2441 case 0x0DDC:
2442 case 0x0DDE: return lex_Matra_post;
2443 default:
2444 return unicode_lex(c);
2448 static const VowelComponents Sinhala_vowels[] = {
2449 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2450 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2451 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2452 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2453 {0x0000, {0x0000,0x0000,0x0}}};
2455 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2457 int cCount = cChars;
2458 int i;
2459 WCHAR *input;
2460 IndicSyllable *syllables = NULL;
2461 int syllable_count = 0;
2463 if (*pcGlyphs != cChars)
2465 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2466 return;
2469 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2471 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2473 /* Step 1: Decompose multi part vowels */
2474 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2476 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2478 /* Step 2: Reorder within Syllables */
2479 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2480 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2482 /* Step 3: Strip dangling joiners */
2483 for (i = 0; i < cCount; i++)
2485 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2486 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2487 input[i] = 0x0020;
2490 /* Step 4: Base Form application to syllables */
2491 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2492 *pcGlyphs = cCount;
2493 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2495 HeapFree(GetProcessHeap(),0,input);
2496 HeapFree(GetProcessHeap(),0,syllables);
2499 static int devanagari_lex(WCHAR c)
2501 switch (c)
2503 case 0x0930: return lex_Ra;
2504 default:
2505 return unicode_lex(c);
2509 static const ConsonantComponents Devanagari_consonants[] ={
2510 {{0x0928, 0x093C, 0x00000}, 0x0929},
2511 {{0x0930, 0x093C, 0x00000}, 0x0931},
2512 {{0x0933, 0x093C, 0x00000}, 0x0934},
2513 {{0x0915, 0x093C, 0x00000}, 0x0958},
2514 {{0x0916, 0x093C, 0x00000}, 0x0959},
2515 {{0x0917, 0x093C, 0x00000}, 0x095A},
2516 {{0x091C, 0x093C, 0x00000}, 0x095B},
2517 {{0x0921, 0x093C, 0x00000}, 0x095C},
2518 {{0x0922, 0x093C, 0x00000}, 0x095D},
2519 {{0x092B, 0x093C, 0x00000}, 0x095E},
2520 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2522 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2524 int cCount = cChars;
2525 WCHAR *input;
2526 IndicSyllable *syllables = NULL;
2527 int syllable_count = 0;
2528 BOOL modern = get_GSUB_Indic2(psa, psc);
2530 if (*pcGlyphs != cChars)
2532 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2533 return;
2536 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2537 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2539 /* Step 1: Compose Consonant and Nukta */
2540 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2541 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2543 /* Step 2: Reorder within Syllables */
2544 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2545 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2546 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2547 *pcGlyphs = cCount;
2549 /* Step 3: Base Form application to syllables */
2550 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2552 HeapFree(GetProcessHeap(),0,input);
2553 HeapFree(GetProcessHeap(),0,syllables);
2556 static int bengali_lex(WCHAR c)
2558 switch (c)
2560 case 0x09B0: return lex_Ra;
2561 default:
2562 return unicode_lex(c);
2566 static const VowelComponents Bengali_vowels[] = {
2567 {0x09CB, {0x09C7,0x09BE,0x0000}},
2568 {0x09CC, {0x09C7,0x09D7,0x0000}},
2569 {0x0000, {0x0000,0x0000,0x0000}}};
2571 static const ConsonantComponents Bengali_consonants[] = {
2572 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2573 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2574 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2575 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2576 {{0x0000,0x0000,0x0000}, 0x0000}};
2578 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2580 int cCount = cChars;
2581 WCHAR *input;
2582 IndicSyllable *syllables = NULL;
2583 int syllable_count = 0;
2584 BOOL modern = get_GSUB_Indic2(psa, psc);
2586 if (*pcGlyphs != cChars)
2588 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2589 return;
2592 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2593 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2595 /* Step 1: Decompose Vowels and Compose Consonents */
2596 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2597 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2598 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2600 /* Step 2: Reorder within Syllables */
2601 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2602 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2603 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2604 *pcGlyphs = cCount;
2606 /* Step 3: Initial form is only applied to the beginning of words */
2607 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2609 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2611 int index = cCount;
2612 int gCount = 1;
2613 if (index > 0) index++;
2615 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2619 /* Step 4: Base Form application to syllables */
2620 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2622 HeapFree(GetProcessHeap(),0,input);
2623 HeapFree(GetProcessHeap(),0,syllables);
2626 static int gurmukhi_lex(WCHAR c)
2628 if (c == 0x0A71)
2629 return lex_Modifier;
2630 else
2631 return unicode_lex(c);
2634 static const ConsonantComponents Gurmukhi_consonants[] = {
2635 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2636 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2637 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2638 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2639 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2640 {{0x0000,0x0000,0x0000}, 0x0000}};
2642 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2644 int cCount = cChars;
2645 WCHAR *input;
2646 IndicSyllable *syllables = NULL;
2647 int syllable_count = 0;
2648 BOOL modern = get_GSUB_Indic2(psa, psc);
2650 if (*pcGlyphs != cChars)
2652 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2653 return;
2656 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2657 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2659 /* Step 1: Compose Consonents */
2660 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2661 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2663 /* Step 2: Reorder within Syllables */
2664 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2665 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2666 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2667 *pcGlyphs = cCount;
2669 /* Step 3: Base Form application to syllables */
2670 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2672 HeapFree(GetProcessHeap(),0,input);
2673 HeapFree(GetProcessHeap(),0,syllables);
2676 static int gujarati_lex(WCHAR c)
2678 switch (c)
2680 case 0x0AB0: return lex_Ra;
2681 default:
2682 return unicode_lex(c);
2686 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2688 int cCount = cChars;
2689 WCHAR *input;
2690 IndicSyllable *syllables = NULL;
2691 int syllable_count = 0;
2692 BOOL modern = get_GSUB_Indic2(psa, psc);
2694 if (*pcGlyphs != cChars)
2696 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2697 return;
2700 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2701 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2703 /* Step 1: Reorder within Syllables */
2704 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2705 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2706 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2707 *pcGlyphs = cCount;
2709 /* Step 2: Base Form application to syllables */
2710 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2712 HeapFree(GetProcessHeap(),0,input);
2713 HeapFree(GetProcessHeap(),0,syllables);
2716 static int oriya_lex(WCHAR c)
2718 switch (c)
2720 case 0x0B30: return lex_Ra;
2721 default:
2722 return unicode_lex(c);
2726 static const VowelComponents Oriya_vowels[] = {
2727 {0x0B48, {0x0B47,0x0B56,0x0000}},
2728 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2729 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2730 {0x0000, {0x0000,0x0000,0x0000}}};
2732 static const ConsonantComponents Oriya_consonants[] = {
2733 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2734 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2735 {{0x0000,0x0000,0x0000}, 0x0000}};
2737 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2739 int cCount = cChars;
2740 WCHAR *input;
2741 IndicSyllable *syllables = NULL;
2742 int syllable_count = 0;
2743 BOOL modern = get_GSUB_Indic2(psa, psc);
2745 if (*pcGlyphs != cChars)
2747 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2748 return;
2751 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2752 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2754 /* Step 1: Decompose Vowels and Compose Consonents */
2755 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2756 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2757 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2759 /* Step 2: Reorder within Syllables */
2760 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2761 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2762 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2763 *pcGlyphs = cCount;
2765 /* Step 3: Base Form application to syllables */
2766 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2768 HeapFree(GetProcessHeap(),0,input);
2769 HeapFree(GetProcessHeap(),0,syllables);
2772 static int tamil_lex(WCHAR c)
2774 return unicode_lex(c);
2777 static const VowelComponents Tamil_vowels[] = {
2778 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2779 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2780 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2781 {0x0000, {0x0000,0x0000,0x0000}}};
2783 static const ConsonantComponents Tamil_consonants[] = {
2784 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2785 {{0x0000,0x0000,0x0000}, 0x0000}};
2787 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2789 int cCount = cChars;
2790 WCHAR *input;
2791 IndicSyllable *syllables = NULL;
2792 int syllable_count = 0;
2793 BOOL modern = get_GSUB_Indic2(psa, psc);
2795 if (*pcGlyphs != cChars)
2797 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2798 return;
2801 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2802 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2804 /* Step 1: Decompose Vowels and Compose Consonents */
2805 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2806 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2807 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2809 /* Step 2: Reorder within Syllables */
2810 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2811 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2812 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2813 *pcGlyphs = cCount;
2815 /* Step 3: Base Form application to syllables */
2816 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2818 HeapFree(GetProcessHeap(),0,input);
2819 HeapFree(GetProcessHeap(),0,syllables);
2822 static int telugu_lex(WCHAR c)
2824 switch (c)
2826 case 0x0C43:
2827 case 0x0C44: return lex_Modifier;
2828 default:
2829 return unicode_lex(c);
2833 static const VowelComponents Telugu_vowels[] = {
2834 {0x0C48, {0x0C46,0x0C56,0x0000}},
2835 {0x0000, {0x0000,0x0000,0x0000}}};
2837 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2839 int cCount = cChars;
2840 WCHAR *input;
2841 IndicSyllable *syllables = NULL;
2842 int syllable_count = 0;
2843 BOOL modern = get_GSUB_Indic2(psa, psc);
2845 if (*pcGlyphs != cChars)
2847 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2848 return;
2851 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2852 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2854 /* Step 1: Decompose Vowels */
2855 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2856 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2858 /* Step 2: Reorder within Syllables */
2859 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2860 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2861 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2862 *pcGlyphs = cCount;
2864 /* Step 3: Base Form application to syllables */
2865 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2867 HeapFree(GetProcessHeap(),0,input);
2868 HeapFree(GetProcessHeap(),0,syllables);
2871 static int kannada_lex(WCHAR c)
2873 switch (c)
2875 case 0x0CB0: return lex_Ra;
2876 default:
2877 return unicode_lex(c);
2881 static const VowelComponents Kannada_vowels[] = {
2882 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2883 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2884 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2885 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2886 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2887 {0x0000, {0x0000,0x0000,0x0000}}};
2889 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2891 int cCount = cChars;
2892 WCHAR *input;
2893 IndicSyllable *syllables = NULL;
2894 int syllable_count = 0;
2895 BOOL modern = get_GSUB_Indic2(psa, psc);
2897 if (*pcGlyphs != cChars)
2899 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2900 return;
2903 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2904 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2906 /* Step 1: Decompose Vowels */
2907 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2908 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2910 /* Step 2: Reorder within Syllables */
2911 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2912 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2913 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2914 *pcGlyphs = cCount;
2916 /* Step 3: Base Form application to syllables */
2917 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2919 HeapFree(GetProcessHeap(),0,input);
2920 HeapFree(GetProcessHeap(),0,syllables);
2923 static int malayalam_lex(WCHAR c)
2925 return unicode_lex(c);
2928 static const VowelComponents Malayalam_vowels[] = {
2929 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2930 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2931 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2932 {0x0000, {0x0000,0x0000,0x0000}}};
2934 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2936 int cCount = cChars;
2937 WCHAR *input;
2938 IndicSyllable *syllables = NULL;
2939 int syllable_count = 0;
2940 BOOL modern = get_GSUB_Indic2(psa, psc);
2942 if (*pcGlyphs != cChars)
2944 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2945 return;
2948 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2949 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2951 /* Step 1: Decompose Vowels */
2952 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2953 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2955 /* Step 2: Reorder within Syllables */
2956 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2957 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2958 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2959 *pcGlyphs = cCount;
2961 /* Step 3: Base Form application to syllables */
2962 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2964 HeapFree(GetProcessHeap(),0,input);
2965 HeapFree(GetProcessHeap(),0,syllables);
2968 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)
2970 int i,k;
2972 for (i = 0; i < cGlyphs; i++)
2974 int char_index[20];
2975 int char_count = 0;
2977 for (k = 0; k < cChars; k++)
2979 if (pwLogClust[k] == i)
2981 char_index[char_count] = k;
2982 char_count++;
2986 if (char_count == 0)
2987 continue;
2989 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2991 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2992 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2994 else
2995 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2998 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2999 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3002 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 )
3004 int i,k;
3005 int initGlyph, finaGlyph;
3006 INT dirR, dirL;
3007 BYTE *spaces;
3009 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3010 memset(spaces,0,cGlyphs);
3012 if (!psa->fLogicalOrder && psa->fRTL)
3014 initGlyph = cGlyphs-1;
3015 finaGlyph = 0;
3016 dirR = 1;
3017 dirL = -1;
3019 else
3021 initGlyph = 0;
3022 finaGlyph = cGlyphs-1;
3023 dirR = -1;
3024 dirL = 1;
3027 for (i = 0; i < cGlyphs; i++)
3029 for (k = 0; k < cChars; k++)
3030 if (pwLogClust[k] == i)
3032 if (pwcChars[k] == 0x0020)
3033 spaces[i] = 1;
3037 for (i = 0; i < cGlyphs; i++)
3039 int char_index[20];
3040 int char_count = 0;
3041 BOOL isInit, isFinal;
3043 for (k = 0; k < cChars; k++)
3045 if (pwLogClust[k] == i)
3047 char_index[char_count] = k;
3048 char_count++;
3052 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3053 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3055 if (char_count == 0)
3056 continue;
3058 if (char_count == 1)
3060 if (pwcChars[char_index[0]] == 0x0020) /* space */
3062 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3063 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3065 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3066 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3067 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3069 if (!isInit && !isFinal)
3070 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3071 else if (isInit)
3072 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3073 else
3074 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3076 else if (!isInit)
3078 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3079 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3080 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3081 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3082 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3083 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3084 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3085 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3086 else
3087 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3089 else if (!isInit && !isFinal)
3090 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3091 else
3092 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3094 else if (char_count == 2)
3096 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3097 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3098 else if (!isInit)
3099 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3100 else
3101 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3103 else if (!isInit && !isFinal)
3104 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3105 else
3106 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3109 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3110 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3111 HeapFree(GetProcessHeap(),0,spaces);
3114 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 )
3116 int i,k;
3117 int finaGlyph;
3118 INT dirL;
3119 BYTE *spaces;
3121 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3122 memset(spaces,0,cGlyphs);
3124 if (!psa->fLogicalOrder && psa->fRTL)
3126 finaGlyph = 0;
3127 dirL = -1;
3129 else
3131 finaGlyph = cGlyphs-1;
3132 dirL = 1;
3135 for (i = 0; i < cGlyphs; i++)
3137 for (k = 0; k < cChars; k++)
3138 if (pwLogClust[k] == i)
3140 if (pwcChars[k] == 0x0020)
3141 spaces[i] = 1;
3145 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3147 for (i = 0; i < cGlyphs; i++)
3149 int char_index[20];
3150 int char_count = 0;
3152 for (k = 0; k < cChars; k++)
3154 if (pwLogClust[k] == i)
3156 char_index[char_count] = k;
3157 char_count++;
3161 if (char_count == 0)
3162 continue;
3164 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3166 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3167 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3169 else if (i == finaGlyph)
3170 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3171 else
3172 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3174 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3175 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3176 pGlyphProp[i].sva.fClusterStart = 0;
3179 HeapFree(GetProcessHeap(),0,spaces);
3180 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3182 /* Do not allow justification between marks and their base */
3183 for (i = 0; i < cGlyphs; i++)
3185 if (!pGlyphProp[i].sva.fClusterStart)
3186 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3190 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)
3192 int i,k;
3194 for (i = 0; i < cGlyphs; i++)
3196 int char_index[20];
3197 int char_count = 0;
3199 for (k = 0; k < cChars; k++)
3201 if (pwLogClust[k] == i)
3203 char_index[char_count] = k;
3204 char_count++;
3208 if (char_count == 0)
3209 continue;
3211 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3213 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3214 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3216 else
3217 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3219 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3220 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3223 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)
3225 int i,k;
3227 for (i = 0; i < cGlyphs; i++)
3229 int char_index[20];
3230 int char_count = 0;
3232 for (k = 0; k < cChars; k++)
3234 if (pwLogClust[k] == i)
3236 char_index[char_count] = k;
3237 char_count++;
3241 if (char_count == 0)
3242 continue;
3244 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3246 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3247 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3249 else
3250 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3252 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3253 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3255 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3256 for (i = 0; i < cGlyphs; i++)
3258 if (!pGlyphProp[i].sva.fClusterStart)
3260 pGlyphProp[i].sva.fDiacritic = 0;
3261 pGlyphProp[i].sva.fZeroWidth = 0;
3266 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)
3268 int i,k;
3270 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3271 for (i = 0; i < cGlyphs; i++)
3273 int char_index[20];
3274 int char_count = 0;
3276 for (k = 0; k < cChars; k++)
3278 if (pwLogClust[k] == i)
3280 char_index[char_count] = k;
3281 char_count++;
3285 if (override_gsub)
3287 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3288 pGlyphProp[i].sva.fDiacritic = FALSE;
3289 pGlyphProp[i].sva.fZeroWidth = FALSE;
3292 if (char_count == 0)
3293 continue;
3295 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3297 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3298 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3300 else
3301 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3303 pGlyphProp[i].sva.fClusterStart = 0;
3304 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3305 switch (lexical(pwcChars[char_index[k]]))
3307 case lex_Matra_pre:
3308 case lex_Matra_post:
3309 case lex_Matra_above:
3310 case lex_Matra_below:
3311 case lex_Modifier:
3312 case lex_Halant:
3313 break;
3314 case lex_ZWJ:
3315 case lex_ZWNJ:
3316 /* check for dangling joiners */
3317 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3318 pGlyphProp[i].sva.fClusterStart = 1;
3319 else
3320 k = char_count;
3321 break;
3322 default:
3323 pGlyphProp[i].sva.fClusterStart = 1;
3324 break;
3328 if (use_syllables)
3330 IndicSyllable *syllables = NULL;
3331 int syllable_count = 0;
3332 BOOL modern = get_GSUB_Indic2(psa, psc);
3334 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3336 for (i = 0; i < syllable_count; i++)
3338 int j;
3339 WORD g = pwLogClust[syllables[i].start];
3340 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3342 if (pwLogClust[j] != g)
3344 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3345 pwLogClust[j] = g;
3350 HeapFree(GetProcessHeap(), 0, syllables);
3353 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3356 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 )
3358 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3361 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 )
3363 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3366 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 )
3368 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3371 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 )
3373 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3376 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 )
3378 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3381 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 )
3383 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3386 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 )
3388 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3391 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 )
3393 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3396 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 )
3398 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3401 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 )
3403 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3406 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)
3408 if (ShapingData[psa->eScript].charGlyphPropProc)
3409 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3410 else
3411 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3414 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3416 if (!psc->GSUB_Table)
3417 psc->GSUB_Table = load_gsub_table(hdc);
3419 if (ShapingData[psa->eScript].contextProc)
3420 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3423 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)
3425 int i;
3426 INT dirL;
3428 if (!rpRangeProperties)
3429 return;
3431 if (!psc->GSUB_Table)
3432 psc->GSUB_Table = load_gsub_table(hdc);
3434 if (!psc->GSUB_Table)
3435 return;
3437 if (!psa->fLogicalOrder && psa->fRTL)
3438 dirL = -1;
3439 else
3440 dirL = 1;
3442 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3444 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3445 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3449 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3451 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3452 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3454 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3457 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3459 const GSUB_Feature *feature;
3460 int i;
3462 if (!ShapingData[psa->eScript].requiredFeatures)
3463 return S_OK;
3465 if (!psc->GSUB_Table)
3466 psc->GSUB_Table = load_gsub_table(hdc);
3468 /* we need to have at least one of the required features */
3469 i = 0;
3470 while (ShapingData[psa->eScript].requiredFeatures[i])
3472 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3473 if (feature)
3474 return S_OK;
3475 i++;
3478 return USP_E_SCRIPT_NOT_IN_FONT;