usp10: Add New Tai Lue script.
[wine/multimedia.git] / dlls / usp10 / shape.c
blobd2926ff2deee9cd5ae198be9dde09aa549272ca7
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},
609 {{ standard_features, 2}, NULL, "tale", "", NULL, NULL},
610 {{ standard_features, 2}, NULL, "talu", "", NULL, NULL},
611 {{ standard_features, 2}, NULL, "talu", "", NULL, NULL},
614 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
616 const GSUB_CoverageFormat1* cf1;
618 cf1 = table;
620 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
622 int count = GET_BE_WORD(cf1->GlyphCount);
623 int i;
624 TRACE("Coverage Format 1, %i glyphs\n",count);
625 for (i = 0; i < count; i++)
626 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
627 return i;
628 return -1;
630 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
632 const GSUB_CoverageFormat2* cf2;
633 int i;
634 int count;
635 cf2 = (const GSUB_CoverageFormat2*)cf1;
637 count = GET_BE_WORD(cf2->RangeCount);
638 TRACE("Coverage Format 2, %i ranges\n",count);
639 for (i = 0; i < count; i++)
641 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
642 return -1;
643 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
644 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
646 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
647 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
650 return -1;
652 else
653 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
655 return -1;
658 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
660 const GSUB_ScriptList *script;
661 const GSUB_Script *deflt = NULL;
662 int i;
663 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
665 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
666 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
668 const GSUB_Script *scr;
669 int offset;
671 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
672 scr = (const GSUB_Script*)((const BYTE*)script + offset);
674 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
675 return scr;
676 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
677 deflt = scr;
679 return deflt;
682 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
684 int i;
685 int offset;
686 const GSUB_LangSys *Lang;
688 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
690 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
692 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
693 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
695 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
696 return Lang;
698 offset = GET_BE_WORD(script->DefaultLangSys);
699 if (offset)
701 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
702 return Lang;
704 return NULL;
707 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
709 int i;
710 const GSUB_FeatureList *feature;
711 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
713 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
714 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
716 int index = GET_BE_WORD(lang->FeatureIndex[i]);
717 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
719 const GSUB_Feature *feat;
720 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
721 return feat;
724 return NULL;
727 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
729 int j;
730 TRACE("Single Substitution Subtable\n");
732 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
734 int offset;
735 const GSUB_SingleSubstFormat1 *ssf1;
736 offset = GET_BE_WORD(look->SubTable[j]);
737 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
738 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
740 int offset = GET_BE_WORD(ssf1->Coverage);
741 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
742 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
744 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
745 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
746 TRACE(" 0x%x\n",glyphs[glyph_index]);
747 return glyph_index + write_dir;
750 else
752 const GSUB_SingleSubstFormat2 *ssf2;
753 INT index;
754 INT offset;
756 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
757 offset = GET_BE_WORD(ssf1->Coverage);
758 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
759 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
760 TRACE(" Coverage index %i\n",index);
761 if (index != -1)
763 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
764 return GSUB_E_NOGLYPH;
766 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
767 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
768 TRACE("0x%x\n",glyphs[glyph_index]);
769 return glyph_index + write_dir;
773 return GSUB_E_NOGLYPH;
776 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
778 int j;
779 TRACE("Multiple Substitution Subtable\n");
781 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
783 int offset, index;
784 const GSUB_MultipleSubstFormat1 *msf1;
785 offset = GET_BE_WORD(look->SubTable[j]);
786 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
788 offset = GET_BE_WORD(msf1->Coverage);
789 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
790 if (index != -1)
792 const GSUB_Sequence *seq;
793 int sub_count;
794 int j;
795 offset = GET_BE_WORD(msf1->Sequence[index]);
796 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
797 sub_count = GET_BE_WORD(seq->GlyphCount);
798 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
800 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
801 glyphs[j] =glyphs[j-(sub_count-1)];
803 for (j = 0; j < sub_count; j++)
804 if (write_dir < 0)
805 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
806 else
807 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
809 *glyph_count = *glyph_count + (sub_count - 1);
811 if (TRACE_ON(uniscribe))
813 for (j = 0; j < sub_count; j++)
814 TRACE(" 0x%x",glyphs[glyph_index+j]);
815 TRACE("\n");
818 return glyph_index + (sub_count * write_dir);
821 return GSUB_E_NOGLYPH;
824 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
826 int j;
827 TRACE("Alternate Substitution Subtable\n");
829 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
831 int offset;
832 const GSUB_AlternateSubstFormat1 *asf1;
833 INT index;
835 offset = GET_BE_WORD(look->SubTable[j]);
836 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
837 offset = GET_BE_WORD(asf1->Coverage);
839 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
840 if (index != -1)
842 const GSUB_AlternateSet *as;
843 offset = GET_BE_WORD(asf1->AlternateSet[index]);
844 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
845 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
846 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
847 return GSUB_E_NOGLYPH;
849 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
850 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
851 TRACE(" 0x%x\n",glyphs[glyph_index]);
852 return glyph_index + write_dir;
855 return GSUB_E_NOGLYPH;
858 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
860 int j;
862 TRACE("Ligature Substitution Subtable\n");
863 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
865 const GSUB_LigatureSubstFormat1 *lsf1;
866 int offset,index;
868 offset = GET_BE_WORD(look->SubTable[j]);
869 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
870 offset = GET_BE_WORD(lsf1->Coverage);
871 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
872 TRACE(" Coverage index %i\n",index);
873 if (index != -1)
875 const GSUB_LigatureSet *ls;
876 int k, count;
878 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
879 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
880 count = GET_BE_WORD(ls->LigatureCount);
881 TRACE(" LigatureSet has %i members\n",count);
882 for (k = 0; k < count; k++)
884 const GSUB_Ligature *lig;
885 int CompCount,l,CompIndex;
887 offset = GET_BE_WORD(ls->Ligature[k]);
888 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
889 CompCount = GET_BE_WORD(lig->CompCount) - 1;
890 CompIndex = glyph_index+write_dir;
891 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
893 int CompGlyph;
894 CompGlyph = GET_BE_WORD(lig->Component[l]);
895 if (CompGlyph != glyphs[CompIndex])
896 break;
897 CompIndex += write_dir;
899 if (l == CompCount)
901 int replaceIdx = glyph_index;
902 if (write_dir < 0)
903 replaceIdx = glyph_index - CompCount;
905 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
906 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
907 TRACE("0x%x\n",glyphs[replaceIdx]);
908 if (CompCount > 0)
910 int j;
911 for (j = replaceIdx + 1; j < *glyph_count; j++)
912 glyphs[j] =glyphs[j+CompCount];
913 *glyph_count = *glyph_count - CompCount;
915 return replaceIdx + write_dir;
920 return GSUB_E_NOGLYPH;
923 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
925 int j;
926 BOOL done = FALSE;
928 TRACE("Chaining Contextual Substitution Subtable\n");
929 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
931 const GSUB_ChainContextSubstFormat1 *ccsf1;
932 int offset;
933 int dirLookahead = write_dir;
934 int dirBacktrack = -1 * write_dir;
936 offset = GET_BE_WORD(look->SubTable[j]);
937 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
938 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
940 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
941 continue;
943 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
945 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
946 continue;
948 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
950 int k;
951 int indexGlyphs;
952 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
953 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
954 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
955 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
956 int newIndex = glyph_index;
958 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
960 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
962 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
964 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
965 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
966 break;
968 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
969 continue;
970 TRACE("Matched Backtrack\n");
972 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
974 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
975 for (k = 0; k < indexGlyphs; k++)
977 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
978 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
979 break;
981 if (k != indexGlyphs)
982 continue;
983 TRACE("Matched IndexGlyphs\n");
985 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
987 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
989 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
990 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
991 break;
993 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
994 continue;
995 TRACE("Matched LookAhead\n");
997 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
999 if (GET_BE_WORD(ccsf3_4->SubstCount))
1001 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
1003 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
1004 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
1006 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1007 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
1008 if (newIndex == -1)
1010 ERR("Chain failed to generate a glyph\n");
1011 continue;
1014 return newIndex;
1016 else return GSUB_E_NOGLYPH;
1019 return -1;
1022 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1024 int offset;
1025 const GSUB_LookupTable *look;
1027 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1028 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1029 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1030 switch(GET_BE_WORD(look->LookupType))
1032 case 1:
1033 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1034 case 2:
1035 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1036 case 3:
1037 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1038 case 4:
1039 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1040 case 6:
1041 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1042 default:
1043 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1045 return GSUB_E_NOGLYPH;
1048 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)
1050 int i;
1051 int out_index = GSUB_E_NOGLYPH;
1052 const GSUB_LookupList *lookup;
1054 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1056 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1057 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1059 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1060 if (out_index != GSUB_E_NOGLYPH)
1061 break;
1063 if (out_index == GSUB_E_NOGLYPH)
1064 TRACE("lookups found no glyphs\n");
1065 else
1067 int out2;
1068 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1069 if (out2!=GSUB_E_NOGLYPH)
1070 out_index = out2;
1072 return out_index;
1075 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1077 UINT charset;
1079 if (psc->userScript != 0)
1081 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1082 return ShapingData[psa->eScript].newOtTag;
1083 else
1084 return (char*)&psc->userScript;
1087 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1088 return ShapingData[psa->eScript].newOtTag;
1090 if (ShapingData[psa->eScript].otTag[0] != 0)
1091 return ShapingData[psa->eScript].otTag;
1094 * fall back to the font charset
1096 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1097 switch (charset)
1099 case ANSI_CHARSET: return "latn";
1100 case BALTIC_CHARSET: return "latn"; /* ?? */
1101 case CHINESEBIG5_CHARSET: return "hani";
1102 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1103 case GB2312_CHARSET: return "hani";
1104 case GREEK_CHARSET: return "grek";
1105 case HANGUL_CHARSET: return "hang";
1106 case RUSSIAN_CHARSET: return "cyrl";
1107 case SHIFTJIS_CHARSET: return "kana";
1108 case TURKISH_CHARSET: return "latn"; /* ?? */
1109 case VIETNAMESE_CHARSET: return "latn";
1110 case JOHAB_CHARSET: return "latn"; /* ?? */
1111 case ARABIC_CHARSET: return "arab";
1112 case HEBREW_CHARSET: return "hebr";
1113 case THAI_CHARSET: return "thai";
1114 default: return "latn";
1118 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1120 const GSUB_Feature *feature;
1121 const char* script;
1122 int i;
1124 script = get_opentype_script(hdc,psa,psc,FALSE);
1126 for (i = 0; i < psc->feature_count; i++)
1128 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1129 return psc->features[i].feature;
1132 feature = NULL;
1134 if (psc->GSUB_Table)
1136 const GSUB_Script *script;
1137 const GSUB_LangSys *language;
1138 int attempt = 2;
1142 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1143 attempt--;
1144 if (script)
1146 if (psc->userLang != 0)
1147 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1148 else
1149 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1150 if (language)
1151 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1153 } while(attempt && !feature);
1155 /* try in the default (latin) table */
1156 if (!feature)
1158 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1159 if (script)
1161 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1162 if (language)
1163 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1168 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1170 psc->feature_count++;
1172 if (psc->features)
1173 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1174 else
1175 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1177 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1178 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1179 psc->features[psc->feature_count - 1].feature = feature;
1180 return feature;
1183 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)
1185 const GSUB_Feature *feature;
1187 feature = load_GSUB_feature(hdc, psa, psc, feat);
1188 if (!feature)
1189 return GSUB_E_NOFEATURE;
1191 TRACE("applying feature %s\n",feat);
1192 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1195 static VOID *load_gsub_table(HDC hdc)
1197 VOID* GSUB_Table = NULL;
1198 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1199 if (length != GDI_ERROR)
1201 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1202 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1203 TRACE("Loaded GSUB table of %i bytes\n",length);
1205 return GSUB_Table;
1208 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)
1210 WORD *glyphs;
1211 INT glyph_count = count;
1212 INT rc;
1214 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1215 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1216 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1217 if (rc > GSUB_E_NOGLYPH)
1218 rc = count - glyph_count;
1219 else
1220 rc = 0;
1222 HeapFree(GetProcessHeap(),0,glyphs);
1223 return rc;
1226 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1228 int offset;
1229 WORD class = 0;
1230 const GDEF_ClassDefFormat1 *cf1;
1232 if (!header)
1233 return 0;
1235 offset = GET_BE_WORD(header->GlyphClassDef);
1236 if (!offset)
1237 return 0;
1239 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1240 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1242 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1244 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1245 if (index < GET_BE_WORD(cf1->GlyphCount))
1246 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1249 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1251 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1252 int i, top;
1253 top = GET_BE_WORD(cf2->ClassRangeCount);
1254 for (i = 0; i < top; i++)
1256 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1257 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1259 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1260 break;
1264 else
1265 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1267 return class;
1270 static VOID *load_gdef_table(HDC hdc)
1272 VOID* GDEF_Table = NULL;
1273 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1274 if (length != GDI_ERROR)
1276 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1277 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1278 TRACE("Loaded GDEF table of %i bytes\n",length);
1280 return GDEF_Table;
1283 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
1285 int i;
1287 if (!psc->GDEF_Table)
1288 psc->GDEF_Table = load_gdef_table(hdc);
1290 for (i = 0; i < cGlyphs; i++)
1292 WORD class;
1293 int char_count = 0;
1294 int k;
1296 for (k = 0; k < cChars; k++)
1297 if (pwLogClust[k] == i)
1298 char_count++;
1300 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1302 switch (class)
1304 case 0:
1305 case BaseGlyph:
1306 pGlyphProp[i].sva.fClusterStart = 1;
1307 pGlyphProp[i].sva.fDiacritic = 0;
1308 pGlyphProp[i].sva.fZeroWidth = 0;
1309 break;
1310 case LigatureGlyph:
1311 pGlyphProp[i].sva.fClusterStart = 1;
1312 pGlyphProp[i].sva.fDiacritic = 0;
1313 pGlyphProp[i].sva.fZeroWidth = 0;
1314 break;
1315 case MarkGlyph:
1316 pGlyphProp[i].sva.fClusterStart = 0;
1317 pGlyphProp[i].sva.fDiacritic = 1;
1318 pGlyphProp[i].sva.fZeroWidth = 1;
1319 break;
1320 case ComponentGlyph:
1321 pGlyphProp[i].sva.fClusterStart = 0;
1322 pGlyphProp[i].sva.fDiacritic = 0;
1323 pGlyphProp[i].sva.fZeroWidth = 0;
1324 break;
1325 default:
1326 ERR("Unknown glyph class %i\n",class);
1327 pGlyphProp[i].sva.fClusterStart = 1;
1328 pGlyphProp[i].sva.fDiacritic = 0;
1329 pGlyphProp[i].sva.fZeroWidth = 0;
1332 if (char_count == 0)
1333 pGlyphProp[i].sva.fClusterStart = 0;
1337 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1339 int i;
1341 for (i = 0; i < cGlyphs; i++)
1343 if (!pGlyphProp[i].sva.fClusterStart)
1345 int j;
1346 for (j = 0; j < cChars; j++)
1348 if (pwLogClust[j] == i)
1350 int k = j;
1351 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1352 k-=1;
1353 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1354 pwLogClust[j] = pwLogClust[k];
1361 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1363 if (changeCount == 0)
1364 return;
1365 else
1367 int i;
1368 int target_glyph = nextIndex - write_dir;
1369 int seeking_glyph;
1370 int target_index = -1;
1371 int replacing_glyph = -1;
1372 int changed = 0;
1373 int top_logclust = 0;
1375 if (changeCount > 0)
1377 if (write_dir > 0)
1378 target_glyph = nextIndex - changeCount;
1379 else
1380 target_glyph = nextIndex + (changeCount + 1);
1383 seeking_glyph = target_glyph;
1384 for (i = 0; i < chars; i++)
1385 if (pwLogClust[i] > top_logclust)
1386 top_logclust = pwLogClust[i];
1388 do {
1389 if (write_dir > 0)
1390 for (i = 0; i < chars; i++)
1392 if (pwLogClust[i] == seeking_glyph)
1394 target_index = i;
1395 break;
1398 else
1399 for (i = chars - 1; i >= 0; i--)
1401 if (pwLogClust[i] == seeking_glyph)
1403 target_index = i;
1404 break;
1407 if (target_index == -1)
1408 seeking_glyph ++;
1410 while (target_index == -1 && seeking_glyph <= top_logclust);
1412 if (target_index == -1)
1414 ERR("Unable to find target glyph\n");
1415 return;
1418 if (changeCount < 0)
1420 /* merge glyphs */
1421 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1423 if (pwLogClust[i] == target_glyph)
1424 continue;
1425 if(pwLogClust[i] == replacing_glyph)
1426 pwLogClust[i] = target_glyph;
1427 else
1429 changed--;
1430 if (changed >= changeCount)
1432 replacing_glyph = pwLogClust[i];
1433 pwLogClust[i] = target_glyph;
1435 else
1436 break;
1440 /* renumber trailing indexes*/
1441 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1443 if (pwLogClust[i] != target_glyph)
1444 pwLogClust[i] += changeCount;
1447 else
1449 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1450 pwLogClust[i] += changeCount;
1455 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 )
1457 if (psc->GSUB_Table)
1459 const GSUB_Feature *feature;
1460 const GSUB_LookupList *lookup;
1461 const GSUB_Header *header = psc->GSUB_Table;
1462 int lookup_index, lookup_count;
1464 feature = load_GSUB_feature(hdc, psa, psc, feat);
1465 if (!feature)
1466 return GSUB_E_NOFEATURE;
1468 TRACE("applying feature %s\n",debugstr_an(feat,4));
1469 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1470 lookup_count = GET_BE_WORD(feature->LookupCount);
1471 TRACE("%i lookups\n", lookup_count);
1472 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1474 int i;
1476 if (write_dir > 0)
1477 i = 0;
1478 else
1479 i = *pcGlyphs-1;
1480 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1481 while(i < *pcGlyphs && i >= 0)
1483 INT nextIndex;
1484 INT prevCount = *pcGlyphs;
1486 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1487 if (*pcGlyphs != prevCount)
1489 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1490 i = nextIndex;
1492 else
1493 i+=write_dir;
1496 return *pcGlyphs;
1498 return GSUB_E_NOFEATURE;
1501 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1503 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1506 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1508 if (i + delta < 0)
1509 return 0;
1510 if ( i+ delta >= cchLen)
1511 return 0;
1513 i += delta;
1515 return chars[i];
1518 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1520 if (i + delta < 0)
1522 if (psa->fLinkBefore)
1523 return jtR;
1524 else
1525 return jtU;
1527 if ( i+ delta >= cchLen)
1529 if (psa->fLinkAfter)
1530 return jtL;
1531 else
1532 return jtU;
1535 i += delta;
1537 if (context_type[i] == jtT)
1538 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1539 else
1540 return context_type[i];
1543 static inline BOOL right_join_causing(CHAR joining_type)
1545 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1548 static inline BOOL left_join_causing(CHAR joining_type)
1550 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1553 static inline BOOL word_break_causing(WCHAR chr)
1555 /* we are working within a string of characters already guareented to
1556 be within one script, Syriac, so we do not worry about any character
1557 other than the space character outside of that range */
1558 return (chr == 0 || chr == 0x20 );
1562 * ContextualShape_Arabic
1564 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1566 CHAR *context_type;
1567 INT *context_shape;
1568 INT dirR, dirL;
1569 int i;
1571 if (*pcGlyphs != cChars)
1573 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1574 return;
1577 if (!psa->fLogicalOrder && psa->fRTL)
1579 dirR = 1;
1580 dirL = -1;
1582 else
1584 dirR = -1;
1585 dirL = 1;
1588 if (!psc->GSUB_Table)
1589 psc->GSUB_Table = load_gsub_table(hdc);
1591 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1592 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1594 for (i = 0; i < cChars; i++)
1595 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1597 for (i = 0; i < cChars; i++)
1599 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1600 context_shape[i] = Xr;
1601 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1602 context_shape[i] = Xl;
1603 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)))
1604 context_shape[i] = Xm;
1605 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1606 context_shape[i] = Xr;
1607 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1608 context_shape[i] = Xl;
1609 else
1610 context_shape[i] = Xn;
1613 /* Contextual Shaping */
1614 i = 0;
1615 while(i < *pcGlyphs)
1617 BOOL shaped = FALSE;
1619 if (psc->GSUB_Table)
1621 INT nextIndex;
1622 INT prevCount = *pcGlyphs;
1623 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1624 if (nextIndex > GSUB_E_NOGLYPH)
1626 i = nextIndex;
1627 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1629 shaped = (nextIndex > GSUB_E_NOGLYPH);
1632 if (!shaped)
1634 if (context_shape[i] == Xn)
1636 WORD newGlyph = pwOutGlyphs[i];
1637 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1639 /* fall back to presentation form B */
1640 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1641 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1642 pwOutGlyphs[i] = newGlyph;
1645 i++;
1649 HeapFree(GetProcessHeap(),0,context_shape);
1650 HeapFree(GetProcessHeap(),0,context_type);
1654 * ContextualShape_Syriac
1657 #define ALAPH 0x710
1658 #define DALATH 0x715
1659 #define RISH 0x72A
1661 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1663 CHAR *context_type;
1664 INT *context_shape;
1665 INT dirR, dirL;
1666 int i;
1668 if (*pcGlyphs != cChars)
1670 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1671 return;
1674 if (!psa->fLogicalOrder && psa->fRTL)
1676 dirR = 1;
1677 dirL = -1;
1679 else
1681 dirR = -1;
1682 dirL = 1;
1685 if (!psc->GSUB_Table)
1686 psc->GSUB_Table = load_gsub_table(hdc);
1688 if (!psc->GSUB_Table)
1689 return;
1691 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1692 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1694 for (i = 0; i < cChars; i++)
1695 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1697 for (i = 0; i < cChars; i++)
1699 if (pwcChars[i] == ALAPH)
1701 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1703 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1704 context_shape[i] = Afj;
1705 else if ( rchar != DALATH && rchar != RISH &&
1706 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1707 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1708 context_shape[i] = Afn;
1709 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1710 context_shape[i] = Afx;
1711 else
1712 context_shape[i] = Xn;
1714 else if (context_type[i] == jtR &&
1715 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1716 context_shape[i] = Xr;
1717 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1718 context_shape[i] = Xl;
1719 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)))
1720 context_shape[i] = Xm;
1721 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1722 context_shape[i] = Xr;
1723 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1724 context_shape[i] = Xl;
1725 else
1726 context_shape[i] = Xn;
1729 /* Contextual Shaping */
1730 i = 0;
1731 while(i < *pcGlyphs)
1733 INT nextIndex;
1734 INT prevCount = *pcGlyphs;
1735 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1736 if (nextIndex > GSUB_E_NOGLYPH)
1738 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1739 i = nextIndex;
1741 else
1742 i++;
1745 HeapFree(GetProcessHeap(),0,context_shape);
1746 HeapFree(GetProcessHeap(),0,context_type);
1750 * ContextualShape_Phags_pa
1753 #define phags_pa_CANDRABINDU 0xA873
1754 #define phags_pa_START 0xA840
1755 #define phags_pa_END 0xA87F
1757 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1759 INT *context_shape;
1760 INT dirR, dirL;
1761 int i;
1763 if (*pcGlyphs != cChars)
1765 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1766 return;
1769 if (!psa->fLogicalOrder && psa->fRTL)
1771 dirR = 1;
1772 dirL = -1;
1774 else
1776 dirR = -1;
1777 dirL = 1;
1780 if (!psc->GSUB_Table)
1781 psc->GSUB_Table = load_gsub_table(hdc);
1783 if (!psc->GSUB_Table)
1784 return;
1786 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1788 for (i = 0; i < cChars; i++)
1790 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1792 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1793 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1794 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1795 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1797 if (jrchar && jlchar)
1798 context_shape[i] = Xm;
1799 else if (jrchar)
1800 context_shape[i] = Xr;
1801 else if (jlchar)
1802 context_shape[i] = Xl;
1803 else
1804 context_shape[i] = Xn;
1806 else
1807 context_shape[i] = -1;
1810 /* Contextual Shaping */
1811 i = 0;
1812 while(i < *pcGlyphs)
1814 if (context_shape[i] >= 0)
1816 INT nextIndex;
1817 INT prevCount = *pcGlyphs;
1818 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1819 if (nextIndex > GSUB_E_NOGLYPH)
1821 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1822 i = nextIndex;
1824 else
1825 i++;
1827 else
1828 i++;
1831 HeapFree(GetProcessHeap(),0,context_shape);
1834 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1836 int i;
1838 /* Replace */
1839 pwOutChars[cWalk] = replacements[0];
1840 cWalk=cWalk+1;
1842 /* Insert */
1843 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1845 int j;
1846 for (j = *pcChars; j > cWalk; j--)
1847 pwOutChars[j] = pwOutChars[j-1];
1848 *pcChars= *pcChars+1;
1849 pwOutChars[cWalk] = replacements[i];
1850 cWalk = cWalk+1;
1854 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1856 int i;
1857 int cWalk;
1859 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1861 for (i = 0; vowels[i].base != 0x0; i++)
1863 if (pwOutChars[cWalk] == vowels[i].base)
1865 int o = 0;
1866 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1867 if (vowels[i].parts[1]) { cWalk++; o++; }
1868 if (vowels[i].parts[2]) { cWalk++; o++; }
1869 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1870 break;
1876 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1878 int i;
1879 int offset = 0;
1880 int cWalk;
1882 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1884 for (i = 0; consonants[i].output!= 0x0; i++)
1886 int j;
1887 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1888 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1889 break;
1891 if (consonants[i].parts[j]==0x0) /* matched all */
1893 int k;
1894 j--;
1895 pwOutChars[cWalk] = consonants[i].output;
1896 for(k = cWalk+1; k < *pcChars - j; k++)
1897 pwOutChars[k] = pwOutChars[k+j];
1898 *pcChars = *pcChars - j;
1899 for (k = j ; k > 0; k--)
1900 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1901 offset += j;
1902 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1903 pwLogClust[k]--;
1904 break;
1907 cWalk++;
1911 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1913 if (s->ralf >= 0)
1915 int j;
1916 WORD Ra = pwChar[s->start];
1917 WORD H = pwChar[s->start+1];
1919 TRACE("Doing reorder of Ra to %i\n",s->base);
1920 for (j = s->start; j < s->base-1; j++)
1921 pwChar[j] = pwChar[j+2];
1922 pwChar[s->base-1] = Ra;
1923 pwChar[s->base] = H;
1925 s->ralf = s->base-1;
1926 s->base -= 2;
1930 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1932 if (s->ralf >= 0)
1934 int j,loc;
1935 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1936 WORD Ra = pwChar[s->start];
1937 WORD H = pwChar[s->start+1];
1938 for (loc = s->end; loc > stop; loc--)
1939 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1940 break;
1942 TRACE("Doing reorder of Ra to %i\n",loc);
1943 for (j = s->start; j < loc-1; j++)
1944 pwChar[j] = pwChar[j+2];
1945 pwChar[loc-1] = Ra;
1946 pwChar[loc] = H;
1948 s->ralf = loc-1;
1949 s->base -= 2;
1950 if (s->blwf >= 0) s->blwf -= 2;
1951 if (s->pref >= 0) s->pref -= 2;
1955 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1957 if (s->ralf >= 0)
1959 int j;
1960 WORD Ra = pwChar[s->start];
1961 WORD H = pwChar[s->start+1];
1963 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1964 for (j = s->start; j < s->end-1; j++)
1965 pwChar[j] = pwChar[j+2];
1966 pwChar[s->end-1] = Ra;
1967 pwChar[s->end] = H;
1969 s->ralf = s->end-1;
1970 s->base -= 2;
1971 if (s->blwf >= 0) s->blwf -= 2;
1972 if (s->pref >= 0) s->pref -= 2;
1976 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1978 int i;
1980 /* reorder Matras */
1981 if (s->end > s->base)
1983 for (i = 1; i <= s->end-s->base; i++)
1985 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1987 int j;
1988 WCHAR c = pwChar[s->base+i];
1989 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1990 for (j = s->base+i; j > s->base; j--)
1991 pwChar[j] = pwChar[j-1];
1992 pwChar[s->base] = c;
1994 if (s->ralf >= s->base) s->ralf++;
1995 if (s->blwf >= s->base) s->blwf++;
1996 if (s->pref >= s->base) s->pref++;
1997 s->base ++;
2003 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2005 int i;
2007 /* reorder Matras */
2008 if (s->end > s->base)
2010 for (i = 1; i <= s->end-s->base; i++)
2012 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2014 int j;
2015 WCHAR c = pwChar[s->base+i];
2016 TRACE("Doing reorder of %x to %i\n",c,s->start);
2017 for (j = s->base+i; j > s->start; j--)
2018 pwChar[j] = pwChar[j-1];
2019 pwChar[s->start] = c;
2021 if (s->ralf >= 0) s->ralf++;
2022 if (s->blwf >= 0) s->blwf++;
2023 if (s->pref >= 0) s->pref++;
2024 s->base ++;
2030 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2032 if (s->blwf >= 0 && g->blwf > g->base)
2034 int j,loc;
2035 int g_offset;
2036 for (loc = s->end; loc > s->blwf; loc--)
2037 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2038 break;
2040 g_offset = (loc - s->blwf) - 1;
2042 if (loc != s->blwf)
2044 WORD blwf = glyphs[g->blwf];
2045 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2046 /* do not care about the pwChar array anymore, just the glyphs */
2047 for (j = 0; j < g_offset; j++)
2048 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2049 glyphs[g->blwf + g_offset] = blwf;
2054 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2056 int i;
2058 /* reorder previously moved Matras to correct position*/
2059 for (i = s->start; i < s->base; i++)
2061 if (lexical(pwChar[i]) == lex_Matra_pre)
2063 int j;
2064 int g_start = g->start + i - s->start;
2065 if (g_start < g->base -1 )
2067 WCHAR og = glyphs[g_start];
2068 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2069 for (j = g_start; j < g->base-1; j++)
2070 glyphs[j] = glyphs[j+1];
2071 glyphs[g->base-1] = og;
2077 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2079 if (s->pref >= 0 && g->pref > g->base)
2081 int j;
2082 WCHAR og = glyphs[g->pref];
2083 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2084 for (j = g->pref; j > g->base; j--)
2085 glyphs[j] = glyphs[j-1];
2086 glyphs[g->base] = og;
2090 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2092 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2093 if (s->start == s->base && s->base == s->end) return;
2094 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2096 Reorder_Ra_follows_base(pwChar, s, lexical);
2097 Reorder_Matra_precede_base(pwChar, s, lexical);
2100 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2102 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2103 if (s->start == s->base && s->base == s->end) return;
2104 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2106 Reorder_Ra_follows_matra(pwChar, s, lexical);
2107 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2110 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2112 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2113 if (s->start == s->base && s->base == s->end) return;
2114 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2116 Reorder_Ra_follows_base(pwChar, s, lexical);
2117 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2120 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2122 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2123 if (s->start == s->base && s->base == s->end) return;
2124 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2126 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2127 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2130 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2132 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2133 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2134 if (s->start == s->base && s->base == s->end) return;
2135 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2137 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2140 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2142 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2143 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2144 if (s->start == s->base && s->base == s->end) return;
2145 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2147 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2148 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2152 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2154 if (shift == 0)
2155 return;
2157 if (glyph_index->start > index)
2158 glyph_index->start += shift;
2159 if (glyph_index->base > index)
2160 glyph_index->base+= shift;
2161 if (glyph_index->end > index)
2162 glyph_index->end+= shift;
2163 if (glyph_index->ralf > index)
2164 glyph_index->ralf+= shift;
2165 if (glyph_index->blwf > index)
2166 glyph_index->blwf+= shift;
2167 if (glyph_index->pref > index)
2168 glyph_index->pref+= shift;
2171 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 )
2173 int index = glyph_index->start;
2175 if (!feature)
2176 return;
2178 while(index <= glyph_index->end)
2180 INT nextIndex;
2181 INT prevCount = *pcGlyphs;
2182 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2183 if (nextIndex > GSUB_E_NOGLYPH)
2185 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2186 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2187 index = nextIndex;
2189 else
2190 index++;
2194 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2196 int i = 0;
2197 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)))))
2198 i++;
2199 if (index + i <= end-1)
2200 return index + i;
2201 else
2202 return -1;
2205 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)
2207 INT index, nextIndex;
2208 INT count,g_offset;
2210 count = syllable->base - syllable->start;
2212 g_offset = 0;
2213 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2214 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2216 INT prevCount = *pcGlyphs;
2217 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2218 if (nextIndex > GSUB_E_NOGLYPH)
2220 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2221 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2222 g_offset += (*pcGlyphs - prevCount);
2225 index+=2;
2226 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2230 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)
2232 INT nextIndex;
2233 INT prevCount = *pcGlyphs;
2235 if (syllable->ralf >= 0)
2237 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2238 if (nextIndex > GSUB_E_NOGLYPH)
2240 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2241 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2246 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2248 int i = 0;
2249 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2250 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2251 is_consonant(lexical(pwChars[index+i+1])))))
2252 i++;
2253 if (index + i <= end-1)
2254 return index+i;
2255 else
2256 return -1;
2259 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)
2261 INT index, nextIndex;
2262 INT count, g_offset=0;
2263 INT ralf = syllable->ralf;
2265 count = syllable->end - syllable->base;
2267 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2269 while (index >= 0)
2271 INT prevCount = *pcGlyphs;
2272 if (ralf >=0 && ralf < index)
2274 g_offset--;
2275 ralf = -1;
2278 if (!modern)
2280 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2281 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2282 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2285 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2286 if (nextIndex > GSUB_E_NOGLYPH)
2288 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2289 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2290 g_offset += (*pcGlyphs - prevCount);
2292 else if (!modern)
2294 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2295 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2296 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2299 index+=2;
2300 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2304 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)
2306 int c;
2307 int overall_shift = 0;
2308 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2309 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2310 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2311 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2312 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2313 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2314 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2315 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2316 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2317 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2318 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2319 IndicSyllable glyph_indexs;
2321 for (c = 0; c < syllable_count; c++)
2323 int old_end;
2324 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2325 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2326 old_end = glyph_indexs.end;
2328 if (locl)
2330 TRACE("applying feature locl\n");
2331 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2333 if (nukt)
2335 TRACE("applying feature nukt\n");
2336 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2338 if (akhn)
2340 TRACE("applying feature akhn\n");
2341 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2344 if (rphf)
2345 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2346 if (rkrf)
2348 TRACE("applying feature rkrf\n");
2349 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2351 if (pref)
2352 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2353 if (blwf)
2355 if (!modern)
2356 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2358 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2361 if (half)
2362 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2363 if (pstf)
2365 TRACE("applying feature pstf\n");
2366 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2368 if (vatu)
2370 TRACE("applying feature vatu\n");
2371 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2373 if (cjct)
2375 TRACE("applying feature cjct\n");
2376 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2379 if (second_reorder)
2380 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2382 overall_shift += glyph_indexs.end - old_end;
2386 static inline int unicode_lex(WCHAR c)
2388 int type;
2390 if (!c) return lex_Generic;
2391 if (c == 0x200D) return lex_ZWJ;
2392 if (c == 0x200C) return lex_ZWNJ;
2393 if (c == 0x00A0) return lex_NBSP;
2395 type = get_table_entry( indic_syllabic_table, c );
2397 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2399 switch( type )
2401 case 0x0d07: /* Unknown */
2402 case 0x0e07: /* Unknwon */
2403 default: return lex_Generic;
2404 case 0x0001:
2405 case 0x0002:
2406 case 0x0011:
2407 case 0x0012:
2408 case 0x0013:
2409 case 0x0014: return lex_Modifier;
2410 case 0x0003:
2411 case 0x0009:
2412 case 0x000a:
2413 case 0x000b:
2414 case 0x000d:
2415 case 0x000e:
2416 case 0x000f:
2417 case 0x0010: return lex_Consonant;
2418 case 0x0004: return lex_Nukta;
2419 case 0x0005: return lex_Halant;
2420 case 0x0006:
2421 case 0x0008: return lex_Vowel;
2422 case 0x0007:
2423 case 0x0107: return lex_Matra_post;
2424 case 0x0207:
2425 case 0x0307: return lex_Matra_pre;
2426 case 0x0807:
2427 case 0x0907:
2428 case 0x0a07:
2429 case 0x0b07:
2430 case 0x0c07:
2431 case 0x0407: return lex_Composed_Vowel;
2432 case 0x0507: return lex_Matra_above;
2433 case 0x0607: return lex_Matra_below;
2434 case 0x000c: return lex_Ra;
2438 static int sinhala_lex(WCHAR c)
2440 switch (c)
2442 case 0x0DDA:
2443 case 0x0DDD:
2444 case 0x0DDC:
2445 case 0x0DDE: return lex_Matra_post;
2446 default:
2447 return unicode_lex(c);
2451 static const VowelComponents Sinhala_vowels[] = {
2452 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2453 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2454 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2455 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2456 {0x0000, {0x0000,0x0000,0x0}}};
2458 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2460 int cCount = cChars;
2461 int i;
2462 WCHAR *input;
2463 IndicSyllable *syllables = NULL;
2464 int syllable_count = 0;
2466 if (*pcGlyphs != cChars)
2468 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2469 return;
2472 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2474 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2476 /* Step 1: Decompose multi part vowels */
2477 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2479 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2481 /* Step 2: Reorder within Syllables */
2482 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2483 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2485 /* Step 3: Strip dangling joiners */
2486 for (i = 0; i < cCount; i++)
2488 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2489 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2490 input[i] = 0x0020;
2493 /* Step 4: Base Form application to syllables */
2494 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2495 *pcGlyphs = cCount;
2496 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2498 HeapFree(GetProcessHeap(),0,input);
2499 HeapFree(GetProcessHeap(),0,syllables);
2502 static int devanagari_lex(WCHAR c)
2504 switch (c)
2506 case 0x0930: return lex_Ra;
2507 default:
2508 return unicode_lex(c);
2512 static const ConsonantComponents Devanagari_consonants[] ={
2513 {{0x0928, 0x093C, 0x00000}, 0x0929},
2514 {{0x0930, 0x093C, 0x00000}, 0x0931},
2515 {{0x0933, 0x093C, 0x00000}, 0x0934},
2516 {{0x0915, 0x093C, 0x00000}, 0x0958},
2517 {{0x0916, 0x093C, 0x00000}, 0x0959},
2518 {{0x0917, 0x093C, 0x00000}, 0x095A},
2519 {{0x091C, 0x093C, 0x00000}, 0x095B},
2520 {{0x0921, 0x093C, 0x00000}, 0x095C},
2521 {{0x0922, 0x093C, 0x00000}, 0x095D},
2522 {{0x092B, 0x093C, 0x00000}, 0x095E},
2523 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2525 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2527 int cCount = cChars;
2528 WCHAR *input;
2529 IndicSyllable *syllables = NULL;
2530 int syllable_count = 0;
2531 BOOL modern = get_GSUB_Indic2(psa, psc);
2533 if (*pcGlyphs != cChars)
2535 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2536 return;
2539 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2540 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2542 /* Step 1: Compose Consonant and Nukta */
2543 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2544 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2546 /* Step 2: Reorder within Syllables */
2547 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2548 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2549 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2550 *pcGlyphs = cCount;
2552 /* Step 3: Base Form application to syllables */
2553 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2555 HeapFree(GetProcessHeap(),0,input);
2556 HeapFree(GetProcessHeap(),0,syllables);
2559 static int bengali_lex(WCHAR c)
2561 switch (c)
2563 case 0x09B0: return lex_Ra;
2564 default:
2565 return unicode_lex(c);
2569 static const VowelComponents Bengali_vowels[] = {
2570 {0x09CB, {0x09C7,0x09BE,0x0000}},
2571 {0x09CC, {0x09C7,0x09D7,0x0000}},
2572 {0x0000, {0x0000,0x0000,0x0000}}};
2574 static const ConsonantComponents Bengali_consonants[] = {
2575 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2576 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2577 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2578 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2579 {{0x0000,0x0000,0x0000}, 0x0000}};
2581 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2583 int cCount = cChars;
2584 WCHAR *input;
2585 IndicSyllable *syllables = NULL;
2586 int syllable_count = 0;
2587 BOOL modern = get_GSUB_Indic2(psa, psc);
2589 if (*pcGlyphs != cChars)
2591 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2592 return;
2595 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2596 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2598 /* Step 1: Decompose Vowels and Compose Consonents */
2599 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2600 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2601 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2603 /* Step 2: Reorder within Syllables */
2604 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2605 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2606 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2607 *pcGlyphs = cCount;
2609 /* Step 3: Initial form is only applied to the beginning of words */
2610 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2612 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2614 int index = cCount;
2615 int gCount = 1;
2616 if (index > 0) index++;
2618 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2622 /* Step 4: Base Form application to syllables */
2623 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2625 HeapFree(GetProcessHeap(),0,input);
2626 HeapFree(GetProcessHeap(),0,syllables);
2629 static int gurmukhi_lex(WCHAR c)
2631 if (c == 0x0A71)
2632 return lex_Modifier;
2633 else
2634 return unicode_lex(c);
2637 static const ConsonantComponents Gurmukhi_consonants[] = {
2638 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2639 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2640 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2641 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2642 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2643 {{0x0000,0x0000,0x0000}, 0x0000}};
2645 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2647 int cCount = cChars;
2648 WCHAR *input;
2649 IndicSyllable *syllables = NULL;
2650 int syllable_count = 0;
2651 BOOL modern = get_GSUB_Indic2(psa, psc);
2653 if (*pcGlyphs != cChars)
2655 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2656 return;
2659 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2660 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2662 /* Step 1: Compose Consonents */
2663 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2664 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2666 /* Step 2: Reorder within Syllables */
2667 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2668 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2669 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2670 *pcGlyphs = cCount;
2672 /* Step 3: Base Form application to syllables */
2673 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2675 HeapFree(GetProcessHeap(),0,input);
2676 HeapFree(GetProcessHeap(),0,syllables);
2679 static int gujarati_lex(WCHAR c)
2681 switch (c)
2683 case 0x0AB0: return lex_Ra;
2684 default:
2685 return unicode_lex(c);
2689 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2691 int cCount = cChars;
2692 WCHAR *input;
2693 IndicSyllable *syllables = NULL;
2694 int syllable_count = 0;
2695 BOOL modern = get_GSUB_Indic2(psa, psc);
2697 if (*pcGlyphs != cChars)
2699 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2700 return;
2703 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2704 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2706 /* Step 1: Reorder within Syllables */
2707 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2708 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2709 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2710 *pcGlyphs = cCount;
2712 /* Step 2: Base Form application to syllables */
2713 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2715 HeapFree(GetProcessHeap(),0,input);
2716 HeapFree(GetProcessHeap(),0,syllables);
2719 static int oriya_lex(WCHAR c)
2721 switch (c)
2723 case 0x0B30: return lex_Ra;
2724 default:
2725 return unicode_lex(c);
2729 static const VowelComponents Oriya_vowels[] = {
2730 {0x0B48, {0x0B47,0x0B56,0x0000}},
2731 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2732 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2733 {0x0000, {0x0000,0x0000,0x0000}}};
2735 static const ConsonantComponents Oriya_consonants[] = {
2736 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2737 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2738 {{0x0000,0x0000,0x0000}, 0x0000}};
2740 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2742 int cCount = cChars;
2743 WCHAR *input;
2744 IndicSyllable *syllables = NULL;
2745 int syllable_count = 0;
2746 BOOL modern = get_GSUB_Indic2(psa, psc);
2748 if (*pcGlyphs != cChars)
2750 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2751 return;
2754 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2755 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2757 /* Step 1: Decompose Vowels and Compose Consonents */
2758 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2759 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2760 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2762 /* Step 2: Reorder within Syllables */
2763 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2764 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2765 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2766 *pcGlyphs = cCount;
2768 /* Step 3: Base Form application to syllables */
2769 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2771 HeapFree(GetProcessHeap(),0,input);
2772 HeapFree(GetProcessHeap(),0,syllables);
2775 static int tamil_lex(WCHAR c)
2777 return unicode_lex(c);
2780 static const VowelComponents Tamil_vowels[] = {
2781 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2782 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2783 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2784 {0x0000, {0x0000,0x0000,0x0000}}};
2786 static const ConsonantComponents Tamil_consonants[] = {
2787 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2788 {{0x0000,0x0000,0x0000}, 0x0000}};
2790 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2792 int cCount = cChars;
2793 WCHAR *input;
2794 IndicSyllable *syllables = NULL;
2795 int syllable_count = 0;
2796 BOOL modern = get_GSUB_Indic2(psa, psc);
2798 if (*pcGlyphs != cChars)
2800 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2801 return;
2804 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2805 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2807 /* Step 1: Decompose Vowels and Compose Consonents */
2808 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2809 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2810 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2812 /* Step 2: Reorder within Syllables */
2813 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2814 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2815 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2816 *pcGlyphs = cCount;
2818 /* Step 3: Base Form application to syllables */
2819 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2821 HeapFree(GetProcessHeap(),0,input);
2822 HeapFree(GetProcessHeap(),0,syllables);
2825 static int telugu_lex(WCHAR c)
2827 switch (c)
2829 case 0x0C43:
2830 case 0x0C44: return lex_Modifier;
2831 default:
2832 return unicode_lex(c);
2836 static const VowelComponents Telugu_vowels[] = {
2837 {0x0C48, {0x0C46,0x0C56,0x0000}},
2838 {0x0000, {0x0000,0x0000,0x0000}}};
2840 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2842 int cCount = cChars;
2843 WCHAR *input;
2844 IndicSyllable *syllables = NULL;
2845 int syllable_count = 0;
2846 BOOL modern = get_GSUB_Indic2(psa, psc);
2848 if (*pcGlyphs != cChars)
2850 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2851 return;
2854 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2855 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2857 /* Step 1: Decompose Vowels */
2858 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2859 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2861 /* Step 2: Reorder within Syllables */
2862 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2863 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2864 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2865 *pcGlyphs = cCount;
2867 /* Step 3: Base Form application to syllables */
2868 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2870 HeapFree(GetProcessHeap(),0,input);
2871 HeapFree(GetProcessHeap(),0,syllables);
2874 static int kannada_lex(WCHAR c)
2876 switch (c)
2878 case 0x0CB0: return lex_Ra;
2879 default:
2880 return unicode_lex(c);
2884 static const VowelComponents Kannada_vowels[] = {
2885 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2886 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2887 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2888 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2889 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2890 {0x0000, {0x0000,0x0000,0x0000}}};
2892 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2894 int cCount = cChars;
2895 WCHAR *input;
2896 IndicSyllable *syllables = NULL;
2897 int syllable_count = 0;
2898 BOOL modern = get_GSUB_Indic2(psa, psc);
2900 if (*pcGlyphs != cChars)
2902 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2903 return;
2906 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2907 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2909 /* Step 1: Decompose Vowels */
2910 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2911 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2913 /* Step 2: Reorder within Syllables */
2914 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2915 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2916 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2917 *pcGlyphs = cCount;
2919 /* Step 3: Base Form application to syllables */
2920 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2922 HeapFree(GetProcessHeap(),0,input);
2923 HeapFree(GetProcessHeap(),0,syllables);
2926 static int malayalam_lex(WCHAR c)
2928 return unicode_lex(c);
2931 static const VowelComponents Malayalam_vowels[] = {
2932 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2933 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2934 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2935 {0x0000, {0x0000,0x0000,0x0000}}};
2937 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2939 int cCount = cChars;
2940 WCHAR *input;
2941 IndicSyllable *syllables = NULL;
2942 int syllable_count = 0;
2943 BOOL modern = get_GSUB_Indic2(psa, psc);
2945 if (*pcGlyphs != cChars)
2947 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2948 return;
2951 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2952 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2954 /* Step 1: Decompose Vowels */
2955 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2956 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2958 /* Step 2: Reorder within Syllables */
2959 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2960 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2961 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2962 *pcGlyphs = cCount;
2964 /* Step 3: Base Form application to syllables */
2965 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2967 HeapFree(GetProcessHeap(),0,input);
2968 HeapFree(GetProcessHeap(),0,syllables);
2971 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)
2973 int i,k;
2975 for (i = 0; i < cGlyphs; i++)
2977 int char_index[20];
2978 int char_count = 0;
2980 for (k = 0; k < cChars; k++)
2982 if (pwLogClust[k] == i)
2984 char_index[char_count] = k;
2985 char_count++;
2989 if (char_count == 0)
2990 continue;
2992 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2994 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2995 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2997 else
2998 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3001 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3002 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3005 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 )
3007 int i,k;
3008 int initGlyph, finaGlyph;
3009 INT dirR, dirL;
3010 BYTE *spaces;
3012 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3013 memset(spaces,0,cGlyphs);
3015 if (!psa->fLogicalOrder && psa->fRTL)
3017 initGlyph = cGlyphs-1;
3018 finaGlyph = 0;
3019 dirR = 1;
3020 dirL = -1;
3022 else
3024 initGlyph = 0;
3025 finaGlyph = cGlyphs-1;
3026 dirR = -1;
3027 dirL = 1;
3030 for (i = 0; i < cGlyphs; i++)
3032 for (k = 0; k < cChars; k++)
3033 if (pwLogClust[k] == i)
3035 if (pwcChars[k] == 0x0020)
3036 spaces[i] = 1;
3040 for (i = 0; i < cGlyphs; i++)
3042 int char_index[20];
3043 int char_count = 0;
3044 BOOL isInit, isFinal;
3046 for (k = 0; k < cChars; k++)
3048 if (pwLogClust[k] == i)
3050 char_index[char_count] = k;
3051 char_count++;
3055 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3056 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3058 if (char_count == 0)
3059 continue;
3061 if (char_count == 1)
3063 if (pwcChars[char_index[0]] == 0x0020) /* space */
3065 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3066 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3068 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3069 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3070 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3072 if (!isInit && !isFinal)
3073 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3074 else if (isInit)
3075 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3076 else
3077 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3079 else if (!isInit)
3081 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3082 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3083 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3084 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3085 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3086 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3087 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3088 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3089 else
3090 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3092 else if (!isInit && !isFinal)
3093 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3094 else
3095 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3097 else if (char_count == 2)
3099 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3100 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3101 else if (!isInit)
3102 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3103 else
3104 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3106 else if (!isInit && !isFinal)
3107 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3108 else
3109 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3112 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3113 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3114 HeapFree(GetProcessHeap(),0,spaces);
3117 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 )
3119 int i,k;
3120 int finaGlyph;
3121 INT dirL;
3122 BYTE *spaces;
3124 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3125 memset(spaces,0,cGlyphs);
3127 if (!psa->fLogicalOrder && psa->fRTL)
3129 finaGlyph = 0;
3130 dirL = -1;
3132 else
3134 finaGlyph = cGlyphs-1;
3135 dirL = 1;
3138 for (i = 0; i < cGlyphs; i++)
3140 for (k = 0; k < cChars; k++)
3141 if (pwLogClust[k] == i)
3143 if (pwcChars[k] == 0x0020)
3144 spaces[i] = 1;
3148 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3150 for (i = 0; i < cGlyphs; i++)
3152 int char_index[20];
3153 int char_count = 0;
3155 for (k = 0; k < cChars; k++)
3157 if (pwLogClust[k] == i)
3159 char_index[char_count] = k;
3160 char_count++;
3164 if (char_count == 0)
3165 continue;
3167 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3169 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3170 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3172 else if (i == finaGlyph)
3173 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3174 else
3175 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3177 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3178 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3179 pGlyphProp[i].sva.fClusterStart = 0;
3182 HeapFree(GetProcessHeap(),0,spaces);
3183 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3185 /* Do not allow justification between marks and their base */
3186 for (i = 0; i < cGlyphs; i++)
3188 if (!pGlyphProp[i].sva.fClusterStart)
3189 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3193 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)
3195 int i,k;
3197 for (i = 0; i < cGlyphs; i++)
3199 int char_index[20];
3200 int char_count = 0;
3202 for (k = 0; k < cChars; k++)
3204 if (pwLogClust[k] == i)
3206 char_index[char_count] = k;
3207 char_count++;
3211 if (char_count == 0)
3212 continue;
3214 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3216 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3217 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3219 else
3220 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3222 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3223 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3226 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)
3228 int i,k;
3230 for (i = 0; i < cGlyphs; i++)
3232 int char_index[20];
3233 int char_count = 0;
3235 for (k = 0; k < cChars; k++)
3237 if (pwLogClust[k] == i)
3239 char_index[char_count] = k;
3240 char_count++;
3244 if (char_count == 0)
3245 continue;
3247 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3249 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3250 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3252 else
3253 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3255 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3256 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3258 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3259 for (i = 0; i < cGlyphs; i++)
3261 if (!pGlyphProp[i].sva.fClusterStart)
3263 pGlyphProp[i].sva.fDiacritic = 0;
3264 pGlyphProp[i].sva.fZeroWidth = 0;
3269 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)
3271 int i,k;
3273 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3274 for (i = 0; i < cGlyphs; i++)
3276 int char_index[20];
3277 int char_count = 0;
3279 for (k = 0; k < cChars; k++)
3281 if (pwLogClust[k] == i)
3283 char_index[char_count] = k;
3284 char_count++;
3288 if (override_gsub)
3290 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3291 pGlyphProp[i].sva.fDiacritic = FALSE;
3292 pGlyphProp[i].sva.fZeroWidth = FALSE;
3295 if (char_count == 0)
3296 continue;
3298 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3300 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3301 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3303 else
3304 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3306 pGlyphProp[i].sva.fClusterStart = 0;
3307 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3308 switch (lexical(pwcChars[char_index[k]]))
3310 case lex_Matra_pre:
3311 case lex_Matra_post:
3312 case lex_Matra_above:
3313 case lex_Matra_below:
3314 case lex_Modifier:
3315 case lex_Halant:
3316 break;
3317 case lex_ZWJ:
3318 case lex_ZWNJ:
3319 /* check for dangling joiners */
3320 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3321 pGlyphProp[i].sva.fClusterStart = 1;
3322 else
3323 k = char_count;
3324 break;
3325 default:
3326 pGlyphProp[i].sva.fClusterStart = 1;
3327 break;
3331 if (use_syllables)
3333 IndicSyllable *syllables = NULL;
3334 int syllable_count = 0;
3335 BOOL modern = get_GSUB_Indic2(psa, psc);
3337 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3339 for (i = 0; i < syllable_count; i++)
3341 int j;
3342 WORD g = pwLogClust[syllables[i].start];
3343 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3345 if (pwLogClust[j] != g)
3347 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3348 pwLogClust[j] = g;
3353 HeapFree(GetProcessHeap(), 0, syllables);
3356 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3359 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 )
3361 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3364 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 )
3366 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3369 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 )
3371 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3374 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 )
3376 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3379 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 )
3381 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3384 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 )
3386 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3389 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 )
3391 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3394 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 )
3396 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3399 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 )
3401 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3404 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 )
3406 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3409 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)
3411 if (ShapingData[psa->eScript].charGlyphPropProc)
3412 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3413 else
3414 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3417 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3419 if (!psc->GSUB_Table)
3420 psc->GSUB_Table = load_gsub_table(hdc);
3422 if (ShapingData[psa->eScript].contextProc)
3423 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3426 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)
3428 int i;
3429 INT dirL;
3431 if (!rpRangeProperties)
3432 return;
3434 if (!psc->GSUB_Table)
3435 psc->GSUB_Table = load_gsub_table(hdc);
3437 if (!psc->GSUB_Table)
3438 return;
3440 if (!psa->fLogicalOrder && psa->fRTL)
3441 dirL = -1;
3442 else
3443 dirL = 1;
3445 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3447 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3448 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3452 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3454 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3455 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3457 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3460 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3462 const GSUB_Feature *feature;
3463 int i;
3465 if (!ShapingData[psa->eScript].requiredFeatures)
3466 return S_OK;
3468 if (!psc->GSUB_Table)
3469 psc->GSUB_Table = load_gsub_table(hdc);
3471 /* we need to have at least one of the required features */
3472 i = 0;
3473 while (ShapingData[psa->eScript].requiredFeatures[i])
3475 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3476 if (feature)
3477 return S_OK;
3478 i++;
3481 return USP_E_SCRIPT_NOT_IN_FONT;