usp10: Refine Ralf reordering location for Devanagari and Gujarati.
[wine.git] / dlls / usp10 / shape.c
blob47700dcc2fdd0361ea5942d37c151097c9d3af60
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_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 );
65 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 );
66 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 );
67 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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
74 extern const unsigned short wine_shaping_table[];
75 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
77 enum joining_types {
78 jtU,
79 jtT,
80 jtR,
81 jtL,
82 jtD,
83 jtC
86 enum joined_forms {
87 Xn=0,
88 Xr,
89 Xl,
90 Xm,
91 /* Syriac Alaph */
92 Afj,
93 Afn,
94 Afx
97 #ifdef WORDS_BIGENDIAN
98 #define GET_BE_WORD(x) (x)
99 #else
100 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
101 #endif
103 /* These are all structures needed for the GSUB table */
104 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
105 #define GSUB_E_NOFEATURE -2
106 #define GSUB_E_NOGLYPH -1
108 typedef struct {
109 DWORD version;
110 WORD ScriptList;
111 WORD FeatureList;
112 WORD LookupList;
113 } GSUB_Header;
115 typedef struct {
116 CHAR ScriptTag[4];
117 WORD Script;
118 } GSUB_ScriptRecord;
120 typedef struct {
121 WORD ScriptCount;
122 GSUB_ScriptRecord ScriptRecord[1];
123 } GSUB_ScriptList;
125 typedef struct {
126 CHAR LangSysTag[4];
127 WORD LangSys;
128 } GSUB_LangSysRecord;
130 typedef struct {
131 WORD DefaultLangSys;
132 WORD LangSysCount;
133 GSUB_LangSysRecord LangSysRecord[1];
134 } GSUB_Script;
136 typedef struct {
137 WORD LookupOrder; /* Reserved */
138 WORD ReqFeatureIndex;
139 WORD FeatureCount;
140 WORD FeatureIndex[1];
141 } GSUB_LangSys;
143 typedef struct {
144 CHAR FeatureTag[4];
145 WORD Feature;
146 } GSUB_FeatureRecord;
148 typedef struct {
149 WORD FeatureCount;
150 GSUB_FeatureRecord FeatureRecord[1];
151 } GSUB_FeatureList;
153 typedef struct {
154 WORD FeatureParams; /* Reserved */
155 WORD LookupCount;
156 WORD LookupListIndex[1];
157 } GSUB_Feature;
159 typedef struct {
160 WORD LookupCount;
161 WORD Lookup[1];
162 } GSUB_LookupList;
164 typedef struct {
165 WORD LookupType;
166 WORD LookupFlag;
167 WORD SubTableCount;
168 WORD SubTable[1];
169 } GSUB_LookupTable;
171 typedef struct {
172 WORD CoverageFormat;
173 WORD GlyphCount;
174 WORD GlyphArray[1];
175 } GSUB_CoverageFormat1;
177 typedef struct {
178 WORD Start;
179 WORD End;
180 WORD StartCoverageIndex;
181 } GSUB_RangeRecord;
183 typedef struct {
184 WORD CoverageFormat;
185 WORD RangeCount;
186 GSUB_RangeRecord RangeRecord[1];
187 } GSUB_CoverageFormat2;
189 typedef struct {
190 WORD SubstFormat; /* = 1 */
191 WORD Coverage;
192 WORD DeltaGlyphID;
193 } GSUB_SingleSubstFormat1;
195 typedef struct {
196 WORD SubstFormat; /* = 2 */
197 WORD Coverage;
198 WORD GlyphCount;
199 WORD Substitute[1];
200 }GSUB_SingleSubstFormat2;
202 typedef struct {
203 WORD SubstFormat; /* = 1 */
204 WORD Coverage;
205 WORD LigSetCount;
206 WORD LigatureSet[1];
207 }GSUB_LigatureSubstFormat1;
209 typedef struct {
210 WORD LigatureCount;
211 WORD Ligature[1];
212 }GSUB_LigatureSet;
214 typedef struct{
215 WORD LigGlyph;
216 WORD CompCount;
217 WORD Component[1];
218 }GSUB_Ligature;
220 typedef struct{
221 WORD SequenceIndex;
222 WORD LookupListIndex;
224 }GSUB_SubstLookupRecord;
226 typedef struct{
227 WORD SubstFormat; /* = 1 */
228 WORD Coverage;
229 WORD ChainSubRuleSetCount;
230 WORD ChainSubRuleSet[1];
231 }GSUB_ChainContextSubstFormat1;
233 typedef struct {
234 WORD SubstFormat; /* = 3 */
235 WORD BacktrackGlyphCount;
236 WORD Coverage[1];
237 }GSUB_ChainContextSubstFormat3_1;
239 typedef struct{
240 WORD InputGlyphCount;
241 WORD Coverage[1];
242 }GSUB_ChainContextSubstFormat3_2;
244 typedef struct{
245 WORD LookaheadGlyphCount;
246 WORD Coverage[1];
247 }GSUB_ChainContextSubstFormat3_3;
249 typedef struct{
250 WORD SubstCount;
251 GSUB_SubstLookupRecord SubstLookupRecord[1];
252 }GSUB_ChainContextSubstFormat3_4;
254 typedef struct {
255 WORD SubstFormat; /* = 1 */
256 WORD Coverage;
257 WORD AlternateSetCount;
258 WORD AlternateSet[1];
259 } GSUB_AlternateSubstFormat1;
261 typedef struct{
262 WORD GlyphCount;
263 WORD Alternate[1];
264 } GSUB_AlternateSet;
266 /* These are all structures needed for the GDEF table */
267 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
269 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
271 typedef struct {
272 DWORD Version;
273 WORD GlyphClassDef;
274 WORD AttachList;
275 WORD LigCaretList;
276 WORD MarkAttachClassDef;
277 } GDEF_Header;
279 typedef struct {
280 WORD ClassFormat;
281 WORD StartGlyph;
282 WORD GlyphCount;
283 WORD ClassValueArray[1];
284 } GDEF_ClassDefFormat1;
286 typedef struct {
287 WORD Start;
288 WORD End;
289 WORD Class;
290 } GDEF_ClassRangeRecord;
292 typedef struct {
293 WORD ClassFormat;
294 WORD ClassRangeCount;
295 GDEF_ClassRangeRecord ClassRangeRecord[1];
296 } GDEF_ClassDefFormat2;
298 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
300 typedef struct tagVowelComponents
302 WCHAR base;
303 WCHAR parts[3];
304 } VowelComponents;
306 typedef struct tagConsonantComponents
308 WCHAR parts[3];
309 WCHAR output;
310 } ConsonantComponents;
312 /* the orders of joined_forms and contextual_features need to line up */
313 static const char* contextual_features[] =
315 "isol",
316 "fina",
317 "init",
318 "medi",
319 /* Syriac Alaph */
320 "med2",
321 "fin2",
322 "fin3"
325 static OPENTYPE_FEATURE_RECORD standard_features[] =
327 { MS_MAKE_TAG('l','i','g','a'), 1},
328 { MS_MAKE_TAG('c','l','i','g'), 1},
331 static OPENTYPE_FEATURE_RECORD arabic_features[] =
333 { MS_MAKE_TAG('r','l','i','g'), 1},
334 { MS_MAKE_TAG('c','a','l','t'), 1},
335 { MS_MAKE_TAG('l','i','g','a'), 1},
336 { MS_MAKE_TAG('d','l','i','g'), 1},
337 { MS_MAKE_TAG('c','s','w','h'), 1},
338 { MS_MAKE_TAG('m','s','e','t'), 1},
341 static const char* required_arabic_features[] =
343 "fina",
344 "init",
345 "medi",
346 "rlig",
347 NULL
350 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
352 { MS_MAKE_TAG('d','l','i','g'), 1},
355 static OPENTYPE_FEATURE_RECORD syriac_features[] =
357 { MS_MAKE_TAG('r','l','i','g'), 1},
358 { MS_MAKE_TAG('c','a','l','t'), 1},
359 { MS_MAKE_TAG('l','i','g','a'), 1},
360 { MS_MAKE_TAG('d','l','i','g'), 1},
363 static const char* required_syriac_features[] =
365 "fina",
366 "fin2",
367 "fin3",
368 "init",
369 "medi",
370 "med2",
371 "rlig",
372 NULL
375 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
377 /* Base forms */
378 { MS_MAKE_TAG('a','k','h','n'), 1},
379 { MS_MAKE_TAG('r','p','h','f'), 1},
380 { MS_MAKE_TAG('v','a','t','u'), 1},
381 { MS_MAKE_TAG('p','s','t','f'), 1},
382 /* Presentation forms */
383 { MS_MAKE_TAG('b','l','w','s'), 1},
384 { MS_MAKE_TAG('a','b','v','s'), 1},
385 { MS_MAKE_TAG('p','s','t','s'), 1},
388 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
390 { MS_MAKE_TAG('a','b','v','s'), 1},
391 { MS_MAKE_TAG('b','l','w','s'), 1},
394 static OPENTYPE_FEATURE_RECORD thai_features[] =
396 { MS_MAKE_TAG('c','c','m','p'), 1},
399 static const char* required_lao_features[] =
401 "ccmp",
402 NULL
405 static const char* required_devanagari_features[] =
407 "nukt",
408 "akhn",
409 "rphf",
410 "blwf",
411 "half",
412 "vatu",
413 "pres",
414 "abvs",
415 "blws",
416 "psts",
417 "haln",
418 NULL
421 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
423 /* Localized forms */
424 { MS_MAKE_TAG('l','o','c','l'), 1},
425 /* Base forms */
426 { MS_MAKE_TAG('n','u','k','t'), 1},
427 { MS_MAKE_TAG('a','k','h','n'), 1},
428 { MS_MAKE_TAG('r','p','h','f'), 1},
429 { MS_MAKE_TAG('r','k','r','f'), 1},
430 { MS_MAKE_TAG('b','l','w','f'), 1},
431 { MS_MAKE_TAG('h','a','l','f'), 1},
432 { MS_MAKE_TAG('v','a','t','u'), 1},
433 { MS_MAKE_TAG('c','j','c','t'), 1},
434 /* Presentation forms */
435 { MS_MAKE_TAG('p','r','e','s'), 1},
436 { MS_MAKE_TAG('a','b','v','s'), 1},
437 { MS_MAKE_TAG('b','l','w','s'), 1},
438 { MS_MAKE_TAG('p','s','t','s'), 1},
439 { MS_MAKE_TAG('h','a','l','n'), 1},
440 { MS_MAKE_TAG('c','a','l','t'), 1},
443 static const char* required_bengali_features[] =
445 "nukt",
446 "akhn",
447 "rphf",
448 "blwf",
449 "half",
450 "vatu",
451 "pstf",
452 "init",
453 "abvs",
454 "blws",
455 "psts",
456 "haln",
457 NULL
460 static OPENTYPE_FEATURE_RECORD bengali_features[] =
462 /* Localized forms */
463 { MS_MAKE_TAG('l','o','c','l'), 1},
464 /* Base forms */
465 { MS_MAKE_TAG('n','u','k','t'), 1},
466 { MS_MAKE_TAG('a','k','h','n'), 1},
467 { MS_MAKE_TAG('r','p','h','f'), 1},
468 { MS_MAKE_TAG('b','l','w','f'), 1},
469 { MS_MAKE_TAG('h','a','l','f'), 1},
470 { MS_MAKE_TAG('p','s','t','f'), 1},
471 { MS_MAKE_TAG('v','a','t','u'), 1},
472 { MS_MAKE_TAG('c','j','c','t'), 1},
473 /* Presentation forms */
474 { MS_MAKE_TAG('i','n','i','t'), 1},
475 { MS_MAKE_TAG('p','r','e','s'), 1},
476 { MS_MAKE_TAG('a','b','v','s'), 1},
477 { MS_MAKE_TAG('b','l','w','s'), 1},
478 { MS_MAKE_TAG('p','s','t','s'), 1},
479 { MS_MAKE_TAG('h','a','l','n'), 1},
480 { MS_MAKE_TAG('c','a','l','t'), 1},
483 static const char* required_gurmukhi_features[] =
485 "nukt",
486 "akhn",
487 "rphf",
488 "blwf",
489 "half",
490 "pstf",
491 "vatu",
492 "cjct",
493 "pres",
494 "abvs",
495 "blws",
496 "psts",
497 "haln",
498 "calt",
499 NULL
502 static OPENTYPE_FEATURE_RECORD gurmukhi_features[] =
504 /* Localized forms */
505 { MS_MAKE_TAG('l','o','c','l'), 1},
506 /* Base forms */
507 { MS_MAKE_TAG('n','u','k','t'), 1},
508 { MS_MAKE_TAG('a','k','h','n'), 1},
509 { MS_MAKE_TAG('r','p','h','f'), 1},
510 { MS_MAKE_TAG('b','l','w','f'), 1},
511 { MS_MAKE_TAG('h','a','l','f'), 1},
512 { MS_MAKE_TAG('p','s','t','f'), 1},
513 { MS_MAKE_TAG('v','a','t','u'), 1},
514 { MS_MAKE_TAG('c','j','c','t'), 1},
515 /* Presentation forms */
516 { MS_MAKE_TAG('p','r','e','s'), 1},
517 { MS_MAKE_TAG('a','b','v','s'), 1},
518 { MS_MAKE_TAG('b','l','w','s'), 1},
519 { MS_MAKE_TAG('p','s','t','s'), 1},
520 { MS_MAKE_TAG('h','a','l','n'), 1},
521 { MS_MAKE_TAG('c','a','l','t'), 1},
524 static const char* required_oriya_features[] =
526 "nukt",
527 "akhn",
528 "rphf",
529 "blwf",
530 "pstf",
531 "cjct",
532 "pres",
533 "abvs",
534 "blws",
535 "psts",
536 "haln",
537 "calt",
538 NULL
541 static OPENTYPE_FEATURE_RECORD oriya_features[] =
543 /* Localized forms */
544 { MS_MAKE_TAG('l','o','c','l'), 1},
545 /* Base forms */
546 { MS_MAKE_TAG('n','u','k','t'), 1},
547 { MS_MAKE_TAG('a','k','h','n'), 1},
548 { MS_MAKE_TAG('r','p','h','f'), 1},
549 { MS_MAKE_TAG('b','l','w','f'), 1},
550 { MS_MAKE_TAG('p','s','t','f'), 1},
551 { MS_MAKE_TAG('c','j','c','t'), 1},
552 /* Presentation forms */
553 { MS_MAKE_TAG('p','r','e','s'), 1},
554 { MS_MAKE_TAG('a','b','v','s'), 1},
555 { MS_MAKE_TAG('b','l','w','s'), 1},
556 { MS_MAKE_TAG('p','s','t','s'), 1},
557 { MS_MAKE_TAG('h','a','l','n'), 1},
558 { MS_MAKE_TAG('c','a','l','t'), 1},
561 static const char* required_tamil_features[] =
563 "nukt",
564 "akhn",
565 "rphf",
566 "pref",
567 "half",
568 "pres",
569 "abvs",
570 "blws",
571 "psts",
572 "haln",
573 "calt",
574 NULL
577 static OPENTYPE_FEATURE_RECORD tamil_features[] =
579 /* Localized forms */
580 { MS_MAKE_TAG('l','o','c','l'), 1},
581 /* Base forms */
582 { MS_MAKE_TAG('n','u','k','t'), 1},
583 { MS_MAKE_TAG('a','k','h','n'), 1},
584 { MS_MAKE_TAG('r','p','h','f'), 1},
585 { MS_MAKE_TAG('p','r','e','f'), 1},
586 { MS_MAKE_TAG('h','a','l','f'), 1},
587 /* Presentation forms */
588 { MS_MAKE_TAG('p','r','e','s'), 1},
589 { MS_MAKE_TAG('a','b','v','s'), 1},
590 { MS_MAKE_TAG('b','l','w','s'), 1},
591 { MS_MAKE_TAG('p','s','t','s'), 1},
592 { MS_MAKE_TAG('h','a','l','n'), 1},
593 { MS_MAKE_TAG('c','a','l','t'), 1},
596 static const char* required_telugu_features[] =
598 "nukt",
599 "akhn",
600 "rphf",
601 "pref",
602 "half",
603 "pstf",
604 "cjct",
605 "pres",
606 "abvs",
607 "blws",
608 "psts",
609 "haln",
610 "calt",
611 NULL
614 static OPENTYPE_FEATURE_RECORD telugu_features[] =
616 /* Localized forms */
617 { MS_MAKE_TAG('l','o','c','l'), 1},
618 /* Base forms */
619 { MS_MAKE_TAG('n','u','k','t'), 1},
620 { MS_MAKE_TAG('a','k','h','n'), 1},
621 { MS_MAKE_TAG('r','p','h','f'), 1},
622 { MS_MAKE_TAG('p','r','e','f'), 1},
623 { MS_MAKE_TAG('b','l','w','f'), 1},
624 { MS_MAKE_TAG('h','a','l','f'), 1},
625 { MS_MAKE_TAG('p','s','t','f'), 1},
626 { MS_MAKE_TAG('c','j','c','t'), 1},
627 /* Presentation forms */
628 { MS_MAKE_TAG('p','r','e','s'), 1},
629 { MS_MAKE_TAG('a','b','v','s'), 1},
630 { MS_MAKE_TAG('b','l','w','s'), 1},
631 { MS_MAKE_TAG('p','s','t','s'), 1},
632 { MS_MAKE_TAG('h','a','l','n'), 1},
633 { MS_MAKE_TAG('c','a','l','t'), 1},
636 typedef struct ScriptShapeDataTag {
637 TEXTRANGE_PROPERTIES defaultTextRange;
638 const char** requiredFeatures;
639 CHAR otTag[5];
640 CHAR newOtTag[5];
641 ContextualShapingProc contextProc;
642 ShapeCharGlyphPropProc charGlyphPropProc;
643 } ScriptShapeData;
645 /* in order of scripts */
646 static const ScriptShapeData ShapingData[] =
648 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
649 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
650 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
651 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
652 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
653 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
654 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
655 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
656 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
657 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
658 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
659 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
660 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
661 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
662 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
663 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
664 {{ sinhala_features, 7}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
665 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
666 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
667 {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
668 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
669 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
670 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
671 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
672 {{ devanagari_features, 15}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
673 {{ devanagari_features, 15}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
674 {{ bengali_features, 16}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
675 {{ bengali_features, 16}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
676 {{ gurmukhi_features, 15}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
677 {{ gurmukhi_features, 15}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
678 {{ devanagari_features, 15}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
679 {{ devanagari_features, 15}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
680 {{ devanagari_features, 15}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
681 {{ oriya_features, 13}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
682 {{ oriya_features, 13}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
683 {{ tamil_features, 12}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
684 {{ tamil_features, 12}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
685 {{ telugu_features, 15}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
686 {{ telugu_features, 15}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
687 {{ telugu_features, 15}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
688 {{ telugu_features, 15}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
689 {{ telugu_features, 15}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
690 {{ telugu_features, 15}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
693 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
695 const GSUB_CoverageFormat1* cf1;
697 cf1 = table;
699 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
701 int count = GET_BE_WORD(cf1->GlyphCount);
702 int i;
703 TRACE("Coverage Format 1, %i glyphs\n",count);
704 for (i = 0; i < count; i++)
705 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
706 return i;
707 return -1;
709 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
711 const GSUB_CoverageFormat2* cf2;
712 int i;
713 int count;
714 cf2 = (const GSUB_CoverageFormat2*)cf1;
716 count = GET_BE_WORD(cf2->RangeCount);
717 TRACE("Coverage Format 2, %i ranges\n",count);
718 for (i = 0; i < count; i++)
720 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
721 return -1;
722 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
723 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
725 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
726 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
729 return -1;
731 else
732 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
734 return -1;
737 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
739 const GSUB_ScriptList *script;
740 const GSUB_Script *deflt = NULL;
741 int i;
742 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
744 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
745 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
747 const GSUB_Script *scr;
748 int offset;
750 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
751 scr = (const GSUB_Script*)((const BYTE*)script + offset);
753 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
754 return scr;
755 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
756 deflt = scr;
758 return deflt;
761 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
763 int i;
764 int offset;
765 const GSUB_LangSys *Lang;
767 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
769 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
771 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
772 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
774 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
775 return Lang;
777 offset = GET_BE_WORD(script->DefaultLangSys);
778 if (offset)
780 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
781 return Lang;
783 return NULL;
786 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
788 int i;
789 const GSUB_FeatureList *feature;
790 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
792 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
793 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
795 int index = GET_BE_WORD(lang->FeatureIndex[i]);
796 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
798 const GSUB_Feature *feat;
799 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
800 return feat;
803 return NULL;
806 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
808 int j;
809 TRACE("Single Substitution Subtable\n");
811 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
813 int offset;
814 const GSUB_SingleSubstFormat1 *ssf1;
815 offset = GET_BE_WORD(look->SubTable[j]);
816 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
817 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
819 int offset = GET_BE_WORD(ssf1->Coverage);
820 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
821 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
823 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
824 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
825 TRACE(" 0x%x\n",glyphs[glyph_index]);
826 return glyph_index + 1;
829 else
831 const GSUB_SingleSubstFormat2 *ssf2;
832 INT index;
833 INT offset;
835 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
836 offset = GET_BE_WORD(ssf1->Coverage);
837 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
838 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
839 TRACE(" Coverage index %i\n",index);
840 if (index != -1)
842 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
843 return GSUB_E_NOGLYPH;
845 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
846 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
847 TRACE("0x%x\n",glyphs[glyph_index]);
848 return glyph_index + 1;
852 return GSUB_E_NOGLYPH;
855 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
857 int j;
858 TRACE("Alternate Substitution Subtable\n");
860 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
862 int offset;
863 const GSUB_AlternateSubstFormat1 *asf1;
864 INT index;
866 offset = GET_BE_WORD(look->SubTable[j]);
867 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
868 offset = GET_BE_WORD(asf1->Coverage);
870 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
871 if (index != -1)
873 const GSUB_AlternateSet *as;
874 offset = GET_BE_WORD(asf1->AlternateSet[index]);
875 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
876 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
877 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
878 return GSUB_E_NOGLYPH;
880 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
881 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
882 TRACE(" 0x%x\n",glyphs[glyph_index]);
883 return glyph_index + 1;
886 return GSUB_E_NOGLYPH;
889 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
891 int j;
893 TRACE("Ligature Substitution Subtable\n");
894 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
896 const GSUB_LigatureSubstFormat1 *lsf1;
897 int offset,index;
899 offset = GET_BE_WORD(look->SubTable[j]);
900 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
901 offset = GET_BE_WORD(lsf1->Coverage);
902 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
903 TRACE(" Coverage index %i\n",index);
904 if (index != -1)
906 const GSUB_LigatureSet *ls;
907 int k, count;
909 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
910 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
911 count = GET_BE_WORD(ls->LigatureCount);
912 TRACE(" LigatureSet has %i members\n",count);
913 for (k = 0; k < count; k++)
915 const GSUB_Ligature *lig;
916 int CompCount,l,CompIndex;
918 offset = GET_BE_WORD(ls->Ligature[k]);
919 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
920 CompCount = GET_BE_WORD(lig->CompCount) - 1;
921 CompIndex = glyph_index+write_dir;
922 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
924 int CompGlyph;
925 CompGlyph = GET_BE_WORD(lig->Component[l]);
926 if (CompGlyph != glyphs[CompIndex])
927 break;
928 CompIndex += write_dir;
930 if (l == CompCount)
932 int replaceIdx = glyph_index;
933 if (write_dir < 0)
934 replaceIdx = glyph_index - CompCount;
936 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
937 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
938 TRACE("0x%x\n",glyphs[replaceIdx]);
939 if (CompCount > 0)
941 int j;
942 for (j = replaceIdx + 1; j < *glyph_count; j++)
943 glyphs[j] =glyphs[j+CompCount];
944 *glyph_count = *glyph_count - CompCount;
946 return replaceIdx + 1;
951 return GSUB_E_NOGLYPH;
954 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
956 int j;
957 BOOL done = FALSE;
959 TRACE("Chaining Contextual Substitution Subtable\n");
960 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
962 const GSUB_ChainContextSubstFormat1 *ccsf1;
963 int offset;
964 int dirLookahead = write_dir;
965 int dirBacktrack = -1 * write_dir;
967 offset = GET_BE_WORD(look->SubTable[j]);
968 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
969 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
971 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
972 continue;
974 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
976 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
977 continue;
979 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
981 int k;
982 int indexGlyphs;
983 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
984 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
985 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
986 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
987 int newIndex = glyph_index;
989 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
991 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
993 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
995 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
996 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
997 break;
999 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
1000 continue;
1001 TRACE("Matched Backtrack\n");
1003 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
1005 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
1006 for (k = 0; k < indexGlyphs; k++)
1008 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
1009 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
1010 break;
1012 if (k != indexGlyphs)
1013 continue;
1014 TRACE("Matched IndexGlyphs\n");
1016 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
1018 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
1020 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
1021 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
1022 break;
1024 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
1025 continue;
1026 TRACE("Matched LookAhead\n");
1028 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
1030 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
1032 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
1033 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
1035 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1036 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
1037 if (newIndex == -1)
1039 ERR("Chain failed to generate a glyph\n");
1040 continue;
1043 return newIndex;
1046 return -1;
1049 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1051 int offset;
1052 const GSUB_LookupTable *look;
1054 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1055 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1056 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1057 switch(GET_BE_WORD(look->LookupType))
1059 case 1:
1060 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1061 case 3:
1062 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1063 case 4:
1064 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1065 case 6:
1066 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1067 default:
1068 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1070 return GSUB_E_NOGLYPH;
1073 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1075 int i;
1076 int out_index = GSUB_E_NOGLYPH;
1077 const GSUB_LookupList *lookup;
1079 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1081 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1082 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1084 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1085 if (out_index != GSUB_E_NOGLYPH)
1086 break;
1088 if (out_index == GSUB_E_NOGLYPH)
1089 TRACE("lookups found no glyphs\n");
1090 else
1092 int out2;
1093 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1094 if (out2!=GSUB_E_NOGLYPH)
1095 out_index = out2;
1097 return out_index;
1100 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1102 UINT charset;
1104 if (psc->userScript != 0)
1106 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1107 return ShapingData[psa->eScript].newOtTag;
1108 else
1109 return (char*)&psc->userScript;
1112 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1113 return ShapingData[psa->eScript].newOtTag;
1115 if (ShapingData[psa->eScript].otTag[0] != 0)
1116 return ShapingData[psa->eScript].otTag;
1119 * fall back to the font charset
1121 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1122 switch (charset)
1124 case ANSI_CHARSET: return "latn";
1125 case BALTIC_CHARSET: return "latn"; /* ?? */
1126 case CHINESEBIG5_CHARSET: return "hani";
1127 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1128 case GB2312_CHARSET: return "hani";
1129 case GREEK_CHARSET: return "grek";
1130 case HANGUL_CHARSET: return "hang";
1131 case RUSSIAN_CHARSET: return "cyrl";
1132 case SHIFTJIS_CHARSET: return "kana";
1133 case TURKISH_CHARSET: return "latn"; /* ?? */
1134 case VIETNAMESE_CHARSET: return "latn";
1135 case JOHAB_CHARSET: return "latn"; /* ?? */
1136 case ARABIC_CHARSET: return "arab";
1137 case HEBREW_CHARSET: return "hebr";
1138 case THAI_CHARSET: return "thai";
1139 default: return "latn";
1143 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1145 const GSUB_Feature *feature;
1146 int i;
1148 for (i = 0; i < psc->feature_count; i++)
1149 if (strncmp(psc->features[i].tag,feat,4)==0)
1150 return psc->features[i].feature;
1152 feature = NULL;
1154 if (psc->GSUB_Table)
1156 const GSUB_Script *script;
1157 const GSUB_LangSys *language;
1158 int attempt = 2;
1162 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1163 attempt--;
1164 if (script)
1166 if (psc->userLang != 0)
1167 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1168 else
1169 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1170 if (language)
1171 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1173 } while(attempt && !feature);
1175 /* try in the default (latin) table */
1176 if (!feature)
1178 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1179 if (script)
1181 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1182 if (language)
1183 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1188 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1190 psc->feature_count++;
1192 if (psc->features)
1193 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1194 else
1195 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1197 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1198 psc->features[psc->feature_count - 1].feature = feature;
1199 return feature;
1202 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)
1204 const GSUB_Feature *feature;
1206 feature = load_GSUB_feature(hdc, psa, psc, feat);
1207 if (!feature)
1208 return GSUB_E_NOFEATURE;
1210 TRACE("applying feature %s\n",feat);
1211 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1214 static VOID *load_gsub_table(HDC hdc)
1216 VOID* GSUB_Table = NULL;
1217 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1218 if (length != GDI_ERROR)
1220 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1221 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1222 TRACE("Loaded GSUB table of %i bytes\n",length);
1224 return GSUB_Table;
1227 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1229 int offset;
1230 WORD class = 0;
1231 const GDEF_ClassDefFormat1 *cf1;
1233 if (!header)
1234 return 0;
1236 offset = GET_BE_WORD(header->GlyphClassDef);
1237 if (!offset)
1238 return 0;
1240 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1241 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1243 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1245 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1246 if (index < GET_BE_WORD(cf1->GlyphCount))
1247 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1250 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1252 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1253 int i, top;
1254 top = GET_BE_WORD(cf2->ClassRangeCount);
1255 for (i = 0; i < top; i++)
1257 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1258 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1260 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1261 break;
1265 else
1266 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1268 return class;
1271 static VOID *load_gdef_table(HDC hdc)
1273 VOID* GDEF_Table = NULL;
1274 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1275 if (length != GDI_ERROR)
1277 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1278 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1279 TRACE("Loaded GDEF table of %i bytes\n",length);
1281 return GDEF_Table;
1284 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1286 int i;
1288 if (!psc->GDEF_Table)
1289 psc->GDEF_Table = load_gdef_table(hdc);
1291 for (i = 0; i < cGlyphs; i++)
1293 WORD class;
1295 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1297 switch (class)
1299 case 0:
1300 case BaseGlyph:
1301 pGlyphProp[i].sva.fClusterStart = 1;
1302 pGlyphProp[i].sva.fDiacritic = 0;
1303 pGlyphProp[i].sva.fZeroWidth = 0;
1304 break;
1305 case LigatureGlyph:
1306 pGlyphProp[i].sva.fClusterStart = 1;
1307 pGlyphProp[i].sva.fDiacritic = 0;
1308 pGlyphProp[i].sva.fZeroWidth = 0;
1309 break;
1310 case MarkGlyph:
1311 pGlyphProp[i].sva.fClusterStart = 0;
1312 pGlyphProp[i].sva.fDiacritic = 1;
1313 pGlyphProp[i].sva.fZeroWidth = 1;
1314 break;
1315 case ComponentGlyph:
1316 pGlyphProp[i].sva.fClusterStart = 0;
1317 pGlyphProp[i].sva.fDiacritic = 0;
1318 pGlyphProp[i].sva.fZeroWidth = 0;
1319 break;
1320 default:
1321 ERR("Unknown glyph class %i\n",class);
1322 pGlyphProp[i].sva.fClusterStart = 1;
1323 pGlyphProp[i].sva.fDiacritic = 0;
1324 pGlyphProp[i].sva.fZeroWidth = 0;
1329 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1331 int i;
1333 for (i = 0; i < cGlyphs; i++)
1335 if (!pGlyphProp[i].sva.fClusterStart)
1337 int j;
1338 for (j = 0; j < cChars; j++)
1340 if (pwLogClust[j] == i)
1342 int k = j;
1343 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1344 k-=1;
1345 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1346 pwLogClust[j] = pwLogClust[k];
1353 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1355 if (changeCount == 0)
1356 return;
1357 else
1359 int i;
1360 int target_glyph = nextIndex - 1;
1361 int target_index = -1;
1362 int replacing_glyph = -1;
1363 int changed = 0;
1365 if (write_dir > 0)
1366 for (i = 0; i < chars; i++)
1368 if (pwLogClust[i] == target_glyph)
1370 target_index = i;
1371 break;
1374 else
1375 for (i = chars - 1; i >= 0; i--)
1377 if (pwLogClust[i] == target_glyph)
1379 target_index = i;
1380 break;
1383 if (target_index == -1)
1385 ERR("Unable to find target glyph\n");
1386 return;
1389 if (changeCount < 0)
1391 /* merge glyphs */
1392 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1394 if (pwLogClust[i] == target_glyph)
1395 continue;
1396 if(pwLogClust[i] == replacing_glyph)
1397 pwLogClust[i] = target_glyph;
1398 else
1400 changed--;
1401 if (changed >= changeCount)
1403 replacing_glyph = pwLogClust[i];
1404 pwLogClust[i] = target_glyph;
1406 else
1407 break;
1412 /* renumber trailing indexes*/
1413 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1415 if (pwLogClust[i] != target_glyph)
1416 pwLogClust[i] += changeCount;
1421 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 )
1423 int i;
1425 if (psc->GSUB_Table)
1427 const GSUB_Feature *feature;
1429 feature = load_GSUB_feature(hdc, psa, psc, feat);
1430 if (!feature)
1431 return GSUB_E_NOFEATURE;
1433 i = 0;
1434 TRACE("applying feature %s\n",debugstr_an(feat,4));
1435 while(i < *pcGlyphs)
1437 INT nextIndex;
1438 INT prevCount = *pcGlyphs;
1439 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1440 if (nextIndex > GSUB_E_NOGLYPH)
1442 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1443 i = nextIndex;
1445 else
1446 i++;
1448 return *pcGlyphs;
1450 return GSUB_E_NOFEATURE;
1453 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1455 if (i + delta < 0)
1456 return 0;
1457 if ( i+ delta >= cchLen)
1458 return 0;
1460 i += delta;
1462 return chars[i];
1465 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1467 if (i + delta < 0)
1469 if (psa->fLinkBefore)
1470 return jtR;
1471 else
1472 return jtU;
1474 if ( i+ delta >= cchLen)
1476 if (psa->fLinkAfter)
1477 return jtL;
1478 else
1479 return jtU;
1482 i += delta;
1484 if (context_type[i] == jtT)
1485 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1486 else
1487 return context_type[i];
1490 static inline BOOL right_join_causing(CHAR joining_type)
1492 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1495 static inline BOOL left_join_causing(CHAR joining_type)
1497 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1500 static inline BOOL word_break_causing(WCHAR chr)
1502 /* we are working within a string of characters already guareented to
1503 be within one script, Syriac, so we do not worry about any characers
1504 other than the space character outside of that range */
1505 return (chr == 0 || chr == 0x20 );
1509 * ContextualShape_Arabic
1511 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1513 CHAR *context_type;
1514 INT *context_shape;
1515 INT dirR, dirL;
1516 int i;
1518 if (*pcGlyphs != cChars)
1520 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1521 return;
1524 if (!psa->fLogicalOrder && psa->fRTL)
1526 dirR = 1;
1527 dirL = -1;
1529 else
1531 dirR = -1;
1532 dirL = 1;
1535 if (!psc->GSUB_Table)
1536 psc->GSUB_Table = load_gsub_table(hdc);
1538 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1539 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1541 for (i = 0; i < cChars; i++)
1542 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1544 for (i = 0; i < cChars; i++)
1546 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1547 context_shape[i] = Xr;
1548 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1549 context_shape[i] = Xl;
1550 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)))
1551 context_shape[i] = Xm;
1552 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1553 context_shape[i] = Xr;
1554 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1555 context_shape[i] = Xl;
1556 else
1557 context_shape[i] = Xn;
1560 /* Contextual Shaping */
1561 i = 0;
1562 while(i < *pcGlyphs)
1564 BOOL shaped = FALSE;
1566 if (psc->GSUB_Table)
1568 INT nextIndex;
1569 INT prevCount = *pcGlyphs;
1570 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1571 if (nextIndex > GSUB_E_NOGLYPH)
1573 i = nextIndex;
1574 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1576 shaped = (nextIndex > GSUB_E_NOGLYPH);
1579 if (!shaped)
1581 WORD newGlyph = pwOutGlyphs[i];
1582 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1584 /* fall back to presentation form B */
1585 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1586 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1587 pwOutGlyphs[i] = newGlyph;
1589 i++;
1593 HeapFree(GetProcessHeap(),0,context_shape);
1594 HeapFree(GetProcessHeap(),0,context_type);
1598 * ContextualShape_Syriac
1601 #define ALAPH 0x710
1602 #define DALATH 0x715
1603 #define RISH 0x72A
1605 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1607 CHAR *context_type;
1608 INT *context_shape;
1609 INT dirR, dirL;
1610 int i;
1612 if (*pcGlyphs != cChars)
1614 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1615 return;
1618 if (!psa->fLogicalOrder && psa->fRTL)
1620 dirR = 1;
1621 dirL = -1;
1623 else
1625 dirR = -1;
1626 dirL = 1;
1629 if (!psc->GSUB_Table)
1630 psc->GSUB_Table = load_gsub_table(hdc);
1632 if (!psc->GSUB_Table)
1633 return;
1635 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1636 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1638 for (i = 0; i < cChars; i++)
1639 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1641 for (i = 0; i < cChars; i++)
1643 if (pwcChars[i] == ALAPH)
1645 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1647 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1648 context_shape[i] = Afj;
1649 else if ( rchar != DALATH && rchar != RISH &&
1650 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1651 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1652 context_shape[i] = Afn;
1653 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1654 context_shape[i] = Afx;
1655 else
1656 context_shape[i] = Xn;
1658 else if (context_type[i] == jtR &&
1659 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1660 context_shape[i] = Xr;
1661 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1662 context_shape[i] = Xl;
1663 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)))
1664 context_shape[i] = Xm;
1665 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1666 context_shape[i] = Xr;
1667 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1668 context_shape[i] = Xl;
1669 else
1670 context_shape[i] = Xn;
1673 /* Contextual Shaping */
1674 i = 0;
1675 while(i < *pcGlyphs)
1677 INT nextIndex;
1678 INT prevCount = *pcGlyphs;
1679 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1680 if (nextIndex > GSUB_E_NOGLYPH)
1682 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1683 i = nextIndex;
1685 else
1686 i++;
1689 HeapFree(GetProcessHeap(),0,context_shape);
1690 HeapFree(GetProcessHeap(),0,context_type);
1694 * ContextualShape_Phags_pa
1697 #define phags_pa_CANDRABINDU 0xA873
1698 #define phags_pa_START 0xA840
1699 #define phags_pa_END 0xA87F
1701 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1703 INT *context_shape;
1704 INT dirR, dirL;
1705 int i;
1707 if (*pcGlyphs != cChars)
1709 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1710 return;
1713 if (!psa->fLogicalOrder && psa->fRTL)
1715 dirR = 1;
1716 dirL = -1;
1718 else
1720 dirR = -1;
1721 dirL = 1;
1724 if (!psc->GSUB_Table)
1725 psc->GSUB_Table = load_gsub_table(hdc);
1727 if (!psc->GSUB_Table)
1728 return;
1730 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1732 for (i = 0; i < cChars; i++)
1734 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1736 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1737 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1738 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1739 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1741 if (jrchar && jlchar)
1742 context_shape[i] = Xm;
1743 else if (jrchar)
1744 context_shape[i] = Xr;
1745 else if (jlchar)
1746 context_shape[i] = Xl;
1747 else
1748 context_shape[i] = Xn;
1750 else
1751 context_shape[i] = -1;
1754 /* Contextual Shaping */
1755 i = 0;
1756 while(i < *pcGlyphs)
1758 if (context_shape[i] >= 0)
1760 INT nextIndex;
1761 INT prevCount = *pcGlyphs;
1762 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1763 if (nextIndex > GSUB_E_NOGLYPH)
1765 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1766 i = nextIndex;
1768 else
1769 i++;
1771 else
1772 i++;
1775 HeapFree(GetProcessHeap(),0,context_shape);
1778 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1780 int i;
1782 /* Replace */
1783 pwOutChars[cWalk] = replacements[0];
1784 cWalk=cWalk+1;
1786 /* Insert */
1787 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1789 int j;
1790 for (j = *pcChars; j > cWalk; j--)
1791 pwOutChars[j] = pwOutChars[j-1];
1792 *pcChars= *pcChars+1;
1793 pwOutChars[cWalk] = replacements[i];
1794 cWalk = cWalk+1;
1798 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1800 int i;
1801 int cWalk;
1803 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1805 for (i = 0; vowels[i].base != 0x0; i++)
1807 if (pwOutChars[cWalk] == vowels[i].base)
1809 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1810 break;
1816 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1818 int i;
1819 int cWalk;
1821 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1823 for (i = 0; consonants[i].output!= 0x0; i++)
1825 int j;
1826 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1827 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1828 break;
1830 if (consonants[i].parts[j]==0x0) /* matched all */
1832 int k;
1833 j--;
1834 pwOutChars[cWalk] = consonants[i].output;
1835 for(k = cWalk+1; k < *pcChars - j; k++)
1836 pwOutChars[k] = pwOutChars[k+j];
1837 *pcChars = *pcChars - j;
1838 break;
1841 cWalk++;
1845 static void Reorder_Ra_follows_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1847 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1849 int j;
1850 WORD Ra = pwChar[start];
1851 WORD H = pwChar[start+1];
1853 TRACE("Doing reorder of Ra to %i\n",main);
1854 for (j = start; j < main-1; j++)
1855 pwChar[j] = pwChar[j+2];
1856 pwChar[main-1] = Ra;
1857 pwChar[main] = H;
1861 static void Reorder_Ra_follows_matra(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1863 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1865 int j,loc;
1866 WORD Ra = pwChar[start];
1867 WORD H = pwChar[start+1];
1868 for (loc = end; loc > main; loc--)
1869 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1870 break;
1872 TRACE("Doing reorder of Ra to %i\n",loc);
1873 for (j = start; j < loc-1; j++)
1874 pwChar[j] = pwChar[j+2];
1875 pwChar[loc-1] = Ra;
1876 pwChar[loc] = H;
1880 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1882 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1884 int j;
1885 WORD Ra = pwChar[start];
1886 WORD H = pwChar[start+1];
1888 TRACE("Doing reorder of Ra to %i\n",end-1);
1889 for (j = start; j < end-1; j++)
1890 pwChar[j] = pwChar[j+2];
1891 pwChar[end-1] = Ra;
1892 pwChar[end] = H;
1896 static void Reorder_Matra_precede_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1898 int i;
1900 /* reorder Matras */
1901 if (end > main)
1903 for (i = 1; i <= end-main; i++)
1905 if (lexical(pwChar[main+i]) == lex_Matra_pre)
1907 int j;
1908 WCHAR c = pwChar[main+i];
1909 TRACE("Doing reorder of %x %x\n",c,pwChar[main]);
1910 for (j = main+i; j > main; j--)
1911 pwChar[j] = pwChar[j-1];
1912 pwChar[main] = c;
1918 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1920 int i;
1922 /* reorder Matras */
1923 if (end > main)
1925 for (i = 1; i <= end-main; i++)
1927 if (lexical(pwChar[main+i]) == lex_Matra_pre)
1929 int j;
1930 WCHAR c = pwChar[main+i];
1931 TRACE("Doing reorder of %x to %i\n",c,start);
1932 for (j = main+i; j > start; j--)
1933 pwChar[j] = pwChar[j-1];
1934 pwChar[start] = c;
1940 static void Reorder_Like_Sinhala(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1942 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1943 if (start == main && main == end) return;
1945 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1946 if (lexical(pwChar[main]) == lex_Vowel) return;
1948 Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1949 Reorder_Matra_precede_base(pwChar, start, main, end, lexical);
1952 static void Reorder_Like_Devanagari(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1954 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1955 if (start == main && main == end) return;
1957 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1958 if (lexical(pwChar[main]) == lex_Vowel) return;
1960 Reorder_Ra_follows_matra(pwChar, start, main, end, lexical);
1961 Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1964 static void Reorder_Like_Bengali(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1966 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1967 if (start == main && main == end) return;
1969 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1970 if (lexical(pwChar[main]) == lex_Vowel) return;
1972 Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1973 Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1976 static void Reorder_Like_Kannada(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1978 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1979 if (start == main && main == end) return;
1981 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1982 if (lexical(pwChar[main]) == lex_Vowel) return;
1984 Reorder_Ra_follows_syllable(pwChar, start, main, end, lexical);
1985 Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1988 static void Reorder_Like_Malayalam(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1990 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1991 if (start == main && main == end) return;
1993 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1994 if (lexical(pwChar[main]) == lex_Vowel) return;
1996 Reorder_Ra_follows_matra(pwChar, start, main, end, lexical);
1997 Reorder_Matra_precede_base(pwChar, start, main, end, lexical);
2000 static int sinhala_lex(WCHAR c)
2002 switch (c)
2004 case 0x0DCA: return lex_Halant;
2005 case 0x0DCF:
2006 case 0x0DDF:
2007 case 0x0DD8: return lex_Matra_post;
2008 case 0x0DD9:
2009 case 0x0DDB: return lex_Matra_pre;
2010 case 0x0DDA:
2011 case 0x0DDC: return lex_Composed_Vowel;
2012 case 0x200D: return lex_ZWJ;
2013 case 0x200C: return lex_ZWNJ;
2014 case 0x00A0: return lex_NBSP;
2015 default:
2016 if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
2017 else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
2018 else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
2019 else if (c>=0x0DD0 && c <=0x0DD1) return lex_Matra_post;
2020 else if (c>=0x0DD2 && c <=0x0DD3) return lex_Matra_above;
2021 else if (c>=0x0DD4 && c <=0x0DD6) return lex_Matra_below;
2022 else if (c>=0x0DDD && c <=0x0DDE) return lex_Composed_Vowel;
2023 else if (c>=0x0DF2 && c <=0x0DF3) return lex_Matra_post;
2024 else return lex_Generic;
2028 static const VowelComponents Sinhala_vowels[] = {
2029 {0x0DDA, {0x0DD9,0x0DCA,0x0}},
2030 {0x0DDC, {0x0DD9,0x0DCF,0x0}},
2031 {0x0DDD, {0x0DD9,0x0DCF,0x0DCA}},
2032 {0x0DDE, {0x0DD9,0x0DDF,0x0}},
2033 {0x0000, {0x0000,0x0000,0x0}}};
2035 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2037 int cCount = cChars;
2038 WCHAR *input;
2040 if (*pcGlyphs != cChars)
2042 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2043 return;
2046 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2048 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2050 /* Step 1: Decompose multi part vowels */
2051 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels);
2053 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2055 /* Step 2: Reorder within Syllables */
2056 Indic_ReorderCharacters( input, cCount, sinhala_lex, Reorder_Like_Sinhala);
2057 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2059 /* Step 3: Get glyphs */
2060 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2061 *pcGlyphs = cCount;
2063 HeapFree(GetProcessHeap(),0,input);
2066 static int devanagari_lex(WCHAR c)
2068 switch (c)
2070 case 0x0951:
2071 case 0x0952:
2072 case 0x0903: return lex_Modifier;
2073 case 0x0930: return lex_Ra;
2074 case 0x093C: return lex_Nukta;
2075 case 0x0940:
2076 case 0x093E: return lex_Matra_post;
2077 case 0x093F: return lex_Matra_pre;
2078 case 0x094D: return lex_Halant;
2079 case 0x0972: return lex_Vowel;
2080 case 0x200C: return lex_ZWNJ;
2081 case 0x200D: return lex_ZWJ;
2082 default:
2083 if (c>=0x0901 && c<=0x0902) return lex_Matra_above;
2084 else if (c>=0x0904 && c<=0x0914) return lex_Vowel;
2085 else if (c>=0x0915 && c<=0x0939) return lex_Consonant;
2086 else if (c>=0x0941 && c<=0x0944) return lex_Matra_below;
2087 else if (c>=0x0945 && c<=0x0948) return lex_Matra_above;
2088 else if (c>=0x0949 && c<=0x094C) return lex_Matra_post;
2089 else if (c>=0x0953 && c<=0x0954) return lex_Modifier;
2090 else if (c>=0x0958 && c<=0x095F) return lex_Consonant;
2091 else if (c>=0x0960 && c<=0x0961) return lex_Vowel;
2092 else if (c>=0x0962 && c<=0x0963) return lex_Matra_below;
2093 else if (c>=0x097B && c<=0x097C) return lex_Consonant;
2094 else if (c>=0x097E && c<=0x097F) return lex_Consonant;
2095 else return lex_Generic;
2099 static const ConsonantComponents Devanagari_consonants[] ={
2100 {{0x0928, 0x093C, 0x00000}, 0x0929},
2101 {{0x0930, 0x093C, 0x00000}, 0x0931},
2102 {{0x0933, 0x093C, 0x00000}, 0x0934},
2103 {{0x0915, 0x093C, 0x00000}, 0x0958},
2104 {{0x0916, 0x093C, 0x00000}, 0x0959},
2105 {{0x0917, 0x093C, 0x00000}, 0x095A},
2106 {{0x091C, 0x093C, 0x00000}, 0x095B},
2107 {{0x0921, 0x093C, 0x00000}, 0x095C},
2108 {{0x0922, 0x093C, 0x00000}, 0x095D},
2109 {{0x092B, 0x093C, 0x00000}, 0x095E},
2110 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2112 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2114 int cCount = cChars;
2115 WCHAR *input;
2117 if (*pcGlyphs != cChars)
2119 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2120 return;
2123 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2124 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2126 /* Step 1: Compose Consonant and Nukta */
2127 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2128 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2130 /* Step 2: Reorder within Syllables */
2131 Indic_ReorderCharacters( input, cCount, devanagari_lex, Reorder_Like_Devanagari);
2132 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2133 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2134 *pcGlyphs = cCount;
2136 HeapFree(GetProcessHeap(),0,input);
2139 static int bengali_lex(WCHAR c)
2141 switch (c)
2143 case 0x0981: return lex_Modifier;
2144 case 0x09AC:
2145 case 0x09AF:
2146 case 0x09CE: return lex_Consonant;
2147 case 0x09B0: return lex_Ra;
2148 case 0x09BC: return lex_Nukta;
2149 case 0x09BF: return lex_Matra_pre;
2150 case 0x09D7:
2151 case 0x09BE:
2152 case 0x09C0: return lex_Matra_post;
2153 case 0x09CD: return lex_Halant;
2154 case 0x200C: return lex_ZWNJ;
2155 case 0x200D: return lex_ZWJ;
2156 default:
2157 if (c>=0x0982 && c<=0x0983) return lex_Matra_post;
2158 else if (c>=0x0985 && c<=0x0994) return lex_Vowel;
2159 else if (c>=0x0995 && c<=0x09B9) return lex_Consonant;
2160 else if (c>=0x09C1 && c<=0x09C4) return lex_Matra_below;
2161 else if (c>=0x09C7 && c<=0x09C8) return lex_Matra_pre;
2162 else if (c>=0x09DC && c<=0x09DF) return lex_Consonant;
2163 else if (c>=0x09E0 && c<=0x09E1) return lex_Vowel;
2164 else if (c>=0x09E2 && c<=0x09E3) return lex_Matra_below;
2165 else if (c>=0x09F0 && c<=0x09F1) return lex_Consonant;
2166 else return lex_Generic;
2170 static const VowelComponents Bengali_vowels[] = {
2171 {0x09CB, {0x09C7,0x09BE,0x0000}},
2172 {0x09CC, {0x09C7,0x09D7,0x0000}},
2173 {0x0000, {0x0000,0x0000,0x0000}}};
2175 static const ConsonantComponents Bengali_consonants[] = {
2176 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2177 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2178 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2179 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2180 {{0x0000,0x0000,0x0000}, 0x0000}};
2182 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2184 int cCount = cChars;
2185 WCHAR *input;
2187 if (*pcGlyphs != cChars)
2189 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2190 return;
2193 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2194 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2196 /* Step 1: Decompose Vowels and Compose Consonents */
2197 DecomposeVowels(hdc, input, &cCount, Bengali_vowels);
2198 ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2199 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2201 /* Step 2: Reorder within Syllables */
2202 Indic_ReorderCharacters( input, cCount, bengali_lex, Reorder_Like_Bengali);
2203 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2204 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2205 *pcGlyphs = cCount;
2207 HeapFree(GetProcessHeap(),0,input);
2210 static int gurmukhi_lex(WCHAR c)
2212 switch (c)
2214 case 0x0A30:
2215 case 0x0A35:
2216 case 0x0A39:
2217 case 0x0A2f: return lex_Consonant;
2218 case 0x0A3C: return lex_Nukta;
2219 case 0x0A3F: return lex_Matra_pre;
2220 case 0x0A03:
2221 case 0x0A3E:
2222 case 0x0A40: return lex_Matra_post;
2223 case 0x0A4D: return lex_Halant;
2224 case 0x0A70:
2225 case 0x0A71: return lex_Modifier;
2226 case 0x200C: return lex_ZWNJ;
2227 case 0x200D: return lex_ZWJ;
2228 default:
2229 if (c>=0x0A01 && c<=0x0A02) return lex_Modifier;
2230 else if (c>=0x0A05 && c<=0x0A14) return lex_Vowel;
2231 else if (c>=0x0A15 && c<=0x0A38) return lex_Consonant;
2232 else if (c>=0x0A41 && c<=0x0A42) return lex_Matra_below;
2233 else if (c>=0x0A47 && c<=0x0A4C) return lex_Matra_above;
2234 else if (c>=0x0A59 && c<=0x0A5E) return lex_Consonant;
2235 else return lex_Generic;
2239 static const ConsonantComponents Gurmukhi_consonants[] = {
2240 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2241 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2242 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2243 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2244 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2245 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2246 {{0x0000,0x0000,0x0000}, 0x0000}};
2248 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2250 int cCount = cChars;
2251 WCHAR *input;
2253 if (*pcGlyphs != cChars)
2255 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2256 return;
2259 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2260 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2262 /* Step 1: Compose Consonents */
2263 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2264 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2266 /* Step 2: Reorder within Syllables */
2267 Indic_ReorderCharacters( input, cCount, gurmukhi_lex, Reorder_Like_Bengali);
2268 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2269 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2270 *pcGlyphs = cCount;
2272 HeapFree(GetProcessHeap(),0,input);
2275 static int gujarati_lex(WCHAR c)
2277 switch (c)
2279 case 0x0A83: return lex_Modifier;
2280 case 0x0AB0: return lex_Ra;
2281 case 0x0ABC: return lex_Nukta;
2282 case 0x0ABF: return lex_Matra_pre;
2283 case 0x0ABE:
2284 case 0x0AC0: return lex_Matra_post;
2285 case 0x0ACD: return lex_Halant;
2286 case 0x200C: return lex_ZWNJ;
2287 case 0x200D: return lex_ZWJ;
2288 default:
2289 if (c>=0x0A81 && c<=0x0A82) return lex_Modifier;
2290 else if (c>=0x0A85 && c<=0x0A94) return lex_Vowel;
2291 else if (c>=0x0A95 && c<=0x0AB9) return lex_Consonant;
2292 else if (c>=0x0AC1 && c<=0x0AC4) return lex_Matra_below;
2293 else if (c>=0x0AC5 && c<=0x0AC8) return lex_Matra_above;
2294 else if (c>=0x0AC9 && c<=0x0ACC) return lex_Matra_post;
2295 else if (c>=0x0AE0 && c<=0x0AE1) return lex_Vowel;
2296 else if (c>=0x0AE2 && c<=0x0AE3) return lex_Matra_below;
2297 else return lex_Generic;
2301 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2303 int cCount = cChars;
2304 WCHAR *input;
2306 if (*pcGlyphs != cChars)
2308 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2309 return;
2312 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2313 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2315 /* Step 1: Reorder within Syllables */
2316 Indic_ReorderCharacters( input, cCount, gujarati_lex, Reorder_Like_Devanagari);
2317 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2318 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2319 *pcGlyphs = cCount;
2321 HeapFree(GetProcessHeap(),0,input);
2324 static int oriya_lex(WCHAR c)
2326 switch (c)
2328 case 0x0B24:
2329 case 0x0B28:
2330 case 0x0B2F:
2331 case 0x0B5F:
2332 case 0x0B71:
2333 case 0x0B33: return lex_Consonant;
2334 case 0x0B30: return lex_Ra;
2335 case 0x0B3C: return lex_Nukta;
2336 case 0x0B3F:
2337 case 0x0B56: return lex_Matra_above;
2338 case 0x0B3E:
2339 case 0x0B57:
2340 case 0x0B40: return lex_Matra_post;
2341 case 0x0B47: return lex_Matra_pre;
2342 case 0x0B4D: return lex_Halant;
2343 case 0x200C: return lex_ZWNJ;
2344 case 0x200D: return lex_ZWJ;
2345 default:
2346 if (c>=0x0B01 && c<=0x0B03) return lex_Modifier;
2347 else if (c>=0x0B05 && c<=0x0B14) return lex_Vowel;
2348 else if (c>=0x0B15 && c<=0x0B39) return lex_Consonant;
2349 else if (c>=0x0B2C && c<=0x0B2E) return lex_Consonant;
2350 else if (c>=0x0B32 && c<=0x0B33) return lex_Consonant;
2351 else if (c>=0x0B41 && c<=0x0B44) return lex_Matra_below;
2352 else if (c>=0x0B48 && c<=0x0B4C) return lex_Composed_Vowel;
2353 else if (c>=0x0B5C && c<=0x0B5D) return lex_Consonant;
2354 else if (c>=0x0B60 && c<=0x0B61) return lex_Vowel;
2355 else if (c>=0x0B62 && c<=0x0B63) return lex_Matra_below;
2356 else return lex_Generic;
2360 static const VowelComponents Oriya_vowels[] = {
2361 {0x0B48, {0x0B47,0x0B56,0x0000}},
2362 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2363 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2364 {0x0000, {0x0000,0x0000,0x0000}}};
2366 static const ConsonantComponents Oriya_consonants[] = {
2367 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2368 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2369 {{0x0000,0x0000,0x0000}, 0x0000}};
2371 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2373 int cCount = cChars;
2374 WCHAR *input;
2376 if (*pcGlyphs != cChars)
2378 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2379 return;
2382 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2383 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2385 /* Step 1: Decompose Vowels and Compose Consonents */
2386 DecomposeVowels(hdc, input, &cCount, Oriya_vowels);
2387 ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2388 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2390 /* Step 2: Reorder within Syllables */
2391 Indic_ReorderCharacters( input, cCount, oriya_lex, Reorder_Like_Bengali);
2392 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2393 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2394 *pcGlyphs = cCount;
2396 HeapFree(GetProcessHeap(),0,input);
2399 static int tamil_lex(WCHAR c)
2401 switch (c)
2403 case 0x0BC0: return lex_Matra_above;
2404 case 0x0BCD: return lex_Halant;
2405 case 0x0BD7: return lex_Matra_post;
2406 case 0x200C: return lex_ZWNJ;
2407 case 0x200D: return lex_ZWJ;
2408 default:
2409 if (c>=0x0B95 && c<=0x0BB9) return lex_Consonant;
2410 else if (c>=0x0BBE && c<=0x0BBF) return lex_Matra_post;
2411 else if (c>=0x0BC1 && c<=0x0BC2) return lex_Matra_below;
2412 else if (c>=0x0BC6 && c<=0x0BC8) return lex_Matra_pre;
2413 else return lex_Generic;
2417 static const VowelComponents Tamil_vowels[] = {
2418 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2419 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2420 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2421 {0x0000, {0x0000,0x0000,0x0000}}};
2423 static const ConsonantComponents Tamil_consonants[] = {
2424 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2425 {{0x0000,0x0000,0x0000}, 0x0000}};
2427 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2429 int cCount = cChars;
2430 WCHAR *input;
2432 if (*pcGlyphs != cChars)
2434 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2435 return;
2438 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2439 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2441 /* Step 1: Decompose Vowels and Compose Consonents */
2442 DecomposeVowels(hdc, input, &cCount, Tamil_vowels);
2443 ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2444 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2446 /* Step 2: Reorder within Syllables */
2447 Indic_ReorderCharacters( input, cCount, tamil_lex, Reorder_Like_Sinhala);
2448 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2449 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2450 *pcGlyphs = cCount;
2452 HeapFree(GetProcessHeap(),0,input);
2455 static int telugu_lex(WCHAR c)
2457 switch (c)
2459 case 0x0C4D: return lex_Halant;
2460 case 0x0C55: return lex_Matra_above;
2461 case 0x0C56: return lex_Matra_below;
2462 case 0x200C: return lex_ZWNJ;
2463 case 0x200D: return lex_ZWJ;
2464 default:
2465 if (c>=0x0C01 && c<=0x0C03) return lex_Matra_post;
2466 else if (c>=0x0C05 && c<=0x0C14) return lex_Vowel;
2467 else if (c>=0x0C15 && c<=0x0C39) return lex_Consonant;
2468 else if (c>=0x0C3E && c<=0x0C40) return lex_Matra_above;
2469 else if (c>=0x0C41 && c<=0x0C44) return lex_Matra_post;
2470 else if (c>=0x0C46 && c<=0x0C47) return lex_Matra_above;
2471 else if (c>=0x0C4A && c<=0x0C4C) return lex_Matra_above;
2472 else if (c>=0x0C58 && c<=0x0C59) return lex_Consonant;
2473 else if (c>=0x0C60 && c<=0x0C61) return lex_Vowel;
2474 else if (c>=0x0C62 && c<=0x0C63) return lex_Matra_below;
2475 else return lex_Generic;
2479 static const VowelComponents Telugu_vowels[] = {
2480 {0x0C48, {0x0C46,0x0C56,0x0000}},
2481 {0x0000, {0x0000,0x0000,0x0000}}};
2483 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2485 int cCount = cChars;
2486 WCHAR *input;
2488 if (*pcGlyphs != cChars)
2490 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2491 return;
2494 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2495 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2497 /* Step 1: Decompose Vowels */
2498 DecomposeVowels(hdc, input, &cCount, Telugu_vowels);
2499 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2501 /* Step 2: Reorder within Syllables */
2502 Indic_ReorderCharacters( input, cCount, telugu_lex, Reorder_Like_Bengali);
2503 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2504 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2505 *pcGlyphs = cCount;
2507 HeapFree(GetProcessHeap(),0,input);
2510 static int kannada_lex(WCHAR c)
2512 switch (c)
2514 case 0x0CB0: return lex_Ra;
2515 case 0x0CBC: return lex_Nukta;
2516 case 0x0CBE: return lex_Matra_post;
2517 case 0x0CBF: return lex_Matra_above;
2518 case 0x0CC6: return lex_Matra_above;
2519 case 0x0CCC: return lex_Matra_above;
2520 case 0x0CCD: return lex_Halant;
2521 case 0x0CCE: return lex_Consonant;
2522 case 0x200C: return lex_ZWNJ;
2523 case 0x200D: return lex_ZWJ;
2524 default:
2525 if (c>=0x0C82 && c<=0x0C83) return lex_Modifier;
2526 else if (c>=0x0C85 && c<=0x0C94) return lex_Vowel;
2527 else if (c>=0x0C95 && c<=0x0CB9) return lex_Consonant;
2528 else if (c>=0x0CC1 && c<=0x0CC4) return lex_Matra_post;
2529 else if (c>=0x0CD5 && c<=0x0CD6) return lex_Modifier;
2530 else if (c>=0x0CE0 && c<=0x0CE1) return lex_Vowel;
2531 else if (c>=0x0CE2 && c<=0x0CE3) return lex_Matra_below;
2532 else return lex_Generic;
2536 static const VowelComponents Kannada_vowels[] = {
2537 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2538 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2539 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2540 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2541 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2542 {0x0000, {0x0000,0x0000,0x0000}}};
2544 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2546 int cCount = cChars;
2547 WCHAR *input;
2549 if (*pcGlyphs != cChars)
2551 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2552 return;
2555 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2556 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2558 /* Step 1: Decompose Vowels */
2559 DecomposeVowels(hdc, input, &cCount, Kannada_vowels);
2560 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2562 /* Step 2: Reorder within Syllables */
2563 Indic_ReorderCharacters( input, cCount, kannada_lex, Reorder_Like_Kannada);
2564 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2565 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2566 *pcGlyphs = cCount;
2568 HeapFree(GetProcessHeap(),0,input);
2571 static int malayalam_lex(WCHAR c)
2573 switch (c)
2575 case 0x0D35: return lex_Consonant;
2576 case 0x0D4D: return lex_Halant;
2577 case 0x0D57: return lex_Matra_post;
2578 case 0x200C: return lex_ZWNJ;
2579 case 0x200D: return lex_ZWJ;
2580 default:
2581 if (c>=0x0D02 && c<=0x0D03) return lex_Modifier;
2582 else if (c>=0x0D05 && c<=0x0D14) return lex_Vowel;
2583 else if (c>=0x0D15 && c<=0x0D39) return lex_Consonant;
2584 else if (c>=0x0D3E && c<=0x0D44) return lex_Matra_post;
2585 else if (c>=0x0D46 && c<=0x0D48) return lex_Matra_pre;
2586 else if (c>=0x0D60 && c<=0x0D61) return lex_Vowel;
2587 else if (c>=0x0D62 && c<=0x0D63) return lex_Matra_below;
2588 else return lex_Generic;
2592 static const VowelComponents Malayalam_vowels[] = {
2593 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2594 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2595 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2596 {0x0000, {0x0000,0x0000,0x0000}}};
2598 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2600 int cCount = cChars;
2601 WCHAR *input;
2603 if (*pcGlyphs != cChars)
2605 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2606 return;
2609 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2610 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2612 /* Step 1: Decompose Vowels */
2613 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels);
2614 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2616 /* Step 2: Reorder within Syllables */
2617 Indic_ReorderCharacters( input, cCount, malayalam_lex, Reorder_Like_Malayalam);
2618 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2619 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2620 *pcGlyphs = cCount;
2622 HeapFree(GetProcessHeap(),0,input);
2625 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)
2627 int i,k;
2629 for (i = 0; i < cGlyphs; i++)
2631 int char_index[20];
2632 int char_count = 0;
2634 for (k = 0; k < cChars; k++)
2636 if (pwLogClust[k] == i)
2638 char_index[char_count] = k;
2639 char_count++;
2643 if (char_count == 0)
2645 FIXME("No chars in this glyph? Must be an error\n");
2646 continue;
2649 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2651 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2652 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2654 else
2655 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2658 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2659 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2662 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 )
2664 int i,k;
2665 int initGlyph, finaGlyph;
2666 INT dirR, dirL;
2667 BYTE *spaces;
2669 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2670 memset(spaces,0,cGlyphs);
2672 if (!psa->fLogicalOrder && psa->fRTL)
2674 initGlyph = cGlyphs-1;
2675 finaGlyph = 0;
2676 dirR = 1;
2677 dirL = -1;
2679 else
2681 initGlyph = 0;
2682 finaGlyph = cGlyphs-1;
2683 dirR = -1;
2684 dirL = 1;
2687 for (i = 0; i < cGlyphs; i++)
2689 for (k = 0; k < cChars; k++)
2690 if (pwLogClust[k] == i)
2692 if (pwcChars[k] == 0x0020)
2693 spaces[i] = 1;
2697 for (i = 0; i < cGlyphs; i++)
2699 int char_index[20];
2700 int char_count = 0;
2701 BOOL isInit, isFinal;
2703 for (k = 0; k < cChars; k++)
2705 if (pwLogClust[k] == i)
2707 char_index[char_count] = k;
2708 char_count++;
2712 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2713 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2715 if (char_count == 0)
2717 FIXME("No chars in this glyph? Must be an error\n");
2718 continue;
2721 if (char_count == 1)
2723 if (pwcChars[char_index[0]] == 0x0020) /* space */
2725 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2726 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2728 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2729 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2730 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2732 if (!isInit && !isFinal)
2733 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2734 else if (isInit)
2735 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2736 else
2737 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2739 else if (!isInit)
2741 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2742 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2743 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2744 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2745 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2746 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2747 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2748 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2749 else
2750 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2752 else if (!isInit && !isFinal)
2753 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2754 else
2755 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2757 else if (char_count == 2)
2759 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2760 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2761 else if (!isInit)
2762 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2763 else
2764 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2766 else if (!isInit && !isFinal)
2767 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2768 else
2769 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2772 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2773 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2774 HeapFree(GetProcessHeap(),0,spaces);
2777 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 )
2779 int i,k;
2780 int finaGlyph;
2781 INT dirL;
2782 BYTE *spaces;
2784 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2785 memset(spaces,0,cGlyphs);
2787 if (!psa->fLogicalOrder && psa->fRTL)
2789 finaGlyph = 0;
2790 dirL = -1;
2792 else
2794 finaGlyph = cGlyphs-1;
2795 dirL = 1;
2798 for (i = 0; i < cGlyphs; i++)
2800 for (k = 0; k < cChars; k++)
2801 if (pwLogClust[k] == i)
2803 if (pwcChars[k] == 0x0020)
2804 spaces[i] = 1;
2808 for (i = 0; i < cGlyphs; i++)
2810 int char_index[20];
2811 int char_count = 0;
2813 for (k = 0; k < cChars; k++)
2815 if (pwLogClust[k] == i)
2817 char_index[char_count] = k;
2818 char_count++;
2822 if (char_count == 0)
2824 FIXME("No chars in this glyph? Must be an error\n");
2825 continue;
2828 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2830 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2831 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2833 else if (i == finaGlyph)
2834 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2835 else
2836 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2839 HeapFree(GetProcessHeap(),0,spaces);
2840 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2841 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2843 /* Do not allow justification between marks and their base */
2844 for (i = 0; i < cGlyphs; i++)
2846 if (!pGlyphProp[i].sva.fClusterStart)
2847 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2851 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)
2853 int i,k;
2855 for (i = 0; i < cGlyphs; i++)
2857 int char_index[20];
2858 int char_count = 0;
2860 for (k = 0; k < cChars; k++)
2862 if (pwLogClust[k] == i)
2864 char_index[char_count] = k;
2865 char_count++;
2869 if (char_count == 0)
2871 FIXME("No chars in this glyph? Must be an error\n");
2872 continue;
2875 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2877 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2878 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2880 else
2881 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2883 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2884 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2887 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)
2889 int i,k;
2891 for (i = 0; i < cGlyphs; i++)
2893 int char_index[20];
2894 int char_count = 0;
2896 for (k = 0; k < cChars; k++)
2898 if (pwLogClust[k] == i)
2900 char_index[char_count] = k;
2901 char_count++;
2905 if (char_count == 0)
2907 FIXME("No chars in this glyph? Must be an error\n");
2908 continue;
2911 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2913 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2914 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2916 else
2917 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2919 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2920 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2922 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2923 for (i = 0; i < cGlyphs; i++)
2925 if (!pGlyphProp[i].sva.fClusterStart)
2927 pGlyphProp[i].sva.fDiacritic = 0;
2928 pGlyphProp[i].sva.fZeroWidth = 0;
2933 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)
2935 int i,k;
2937 for (i = 0; i < cGlyphs; i++)
2939 int char_index[20];
2940 int char_count = 0;
2942 for (k = 0; k < cChars; k++)
2944 if (pwLogClust[k] == i)
2946 char_index[char_count] = k;
2947 char_count++;
2951 if (char_count == 0)
2953 FIXME("No chars in this glyph? Must be an error\n");
2954 continue;
2957 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2959 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2960 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2962 else
2963 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2965 pGlyphProp[i].sva.fClusterStart = 0;
2966 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2967 switch (lexical(pwcChars[char_index[k]]))
2969 case lex_Matra_pre:
2970 case lex_Matra_post:
2971 case lex_Matra_above:
2972 case lex_Matra_below:
2973 case lex_Modifier:
2974 break;
2975 default:
2976 pGlyphProp[i].sva.fClusterStart = 1;
2977 break;
2980 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2983 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 )
2985 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
2988 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 )
2990 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
2993 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 )
2995 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
2998 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 )
3000 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3003 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 )
3005 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3008 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 )
3010 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3013 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 )
3015 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3018 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 )
3020 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3023 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 )
3025 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3028 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)
3030 if (ShapingData[psa->eScript].charGlyphPropProc)
3031 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3032 else
3033 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3036 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3038 if (ShapingData[psa->eScript].contextProc)
3039 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3042 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)
3044 int i;
3045 INT dirL;
3047 if (!rpRangeProperties)
3048 return;
3050 if (!psc->GSUB_Table)
3051 psc->GSUB_Table = load_gsub_table(hdc);
3053 if (!psc->GSUB_Table)
3054 return;
3056 if (!psa->fLogicalOrder && psa->fRTL)
3057 dirL = -1;
3058 else
3059 dirL = 1;
3061 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3063 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3064 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3068 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3070 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3071 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3073 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3076 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3078 const GSUB_Feature *feature;
3079 int i;
3081 if (!ShapingData[psa->eScript].requiredFeatures)
3082 return S_OK;
3084 if (!psc->GSUB_Table)
3085 psc->GSUB_Table = load_gsub_table(hdc);
3087 /* we need to have at least one of the required features */
3088 i = 0;
3089 while (ShapingData[psa->eScript].requiredFeatures[i])
3091 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3092 if (feature)
3093 return S_OK;
3094 i++;
3097 return USP_E_SCRIPT_NOT_IN_FONT;