usp10: Correct matra type for Oriya 0x0B57.
[wine/multimedia.git] / dlls / usp10 / shape.c
blobd4f7d177f3d6d05275ba0d93e2fa56868cca001b
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, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1286 VOID* header = load_gdef_table(hdc);
1287 int i;
1289 for (i = 0; i < cGlyphs; i++)
1291 WORD class;
1293 class = GDEF_get_glyph_class(header, pwGlyphs[i]);
1295 switch (class)
1297 case 0:
1298 case BaseGlyph:
1299 pGlyphProp[i].sva.fClusterStart = 1;
1300 pGlyphProp[i].sva.fDiacritic = 0;
1301 pGlyphProp[i].sva.fZeroWidth = 0;
1302 break;
1303 case LigatureGlyph:
1304 pGlyphProp[i].sva.fClusterStart = 1;
1305 pGlyphProp[i].sva.fDiacritic = 0;
1306 pGlyphProp[i].sva.fZeroWidth = 0;
1307 break;
1308 case MarkGlyph:
1309 pGlyphProp[i].sva.fClusterStart = 0;
1310 pGlyphProp[i].sva.fDiacritic = 1;
1311 pGlyphProp[i].sva.fZeroWidth = 1;
1312 break;
1313 case ComponentGlyph:
1314 pGlyphProp[i].sva.fClusterStart = 0;
1315 pGlyphProp[i].sva.fDiacritic = 0;
1316 pGlyphProp[i].sva.fZeroWidth = 0;
1317 break;
1318 default:
1319 ERR("Unknown glyph class %i\n",class);
1320 pGlyphProp[i].sva.fClusterStart = 1;
1321 pGlyphProp[i].sva.fDiacritic = 0;
1322 pGlyphProp[i].sva.fZeroWidth = 0;
1327 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1329 int i;
1331 for (i = 0; i < cGlyphs; i++)
1333 if (!pGlyphProp[i].sva.fClusterStart)
1335 int j;
1336 for (j = 0; j < cChars; j++)
1338 if (pwLogClust[j] == i)
1340 int k = j;
1341 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1342 k-=1;
1343 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1344 pwLogClust[j] = pwLogClust[k];
1351 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1353 if (changeCount == 0)
1354 return;
1355 else
1357 int i;
1358 int target_glyph = nextIndex - 1;
1359 int target_index = -1;
1360 int replacing_glyph = -1;
1361 int changed = 0;
1363 if (write_dir > 0)
1364 for (i = 0; i < chars; i++)
1366 if (pwLogClust[i] == target_glyph)
1368 target_index = i;
1369 break;
1372 else
1373 for (i = chars - 1; i >= 0; i--)
1375 if (pwLogClust[i] == target_glyph)
1377 target_index = i;
1378 break;
1381 if (target_index == -1)
1383 ERR("Unable to find target glyph\n");
1384 return;
1387 if (changeCount < 0)
1389 /* merge glyphs */
1390 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1392 if (pwLogClust[i] == target_glyph)
1393 continue;
1394 if(pwLogClust[i] == replacing_glyph)
1395 pwLogClust[i] = target_glyph;
1396 else
1398 changed--;
1399 if (changed >= changeCount)
1401 replacing_glyph = pwLogClust[i];
1402 pwLogClust[i] = target_glyph;
1404 else
1405 break;
1410 /* renumber trailing indexes*/
1411 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1413 if (pwLogClust[i] != target_glyph)
1414 pwLogClust[i] += changeCount;
1419 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 )
1421 int i;
1423 if (psc->GSUB_Table)
1425 const GSUB_Feature *feature;
1427 feature = load_GSUB_feature(hdc, psa, psc, feat);
1428 if (!feature)
1429 return GSUB_E_NOFEATURE;
1431 i = 0;
1432 TRACE("applying feature %s\n",debugstr_an(feat,4));
1433 while(i < *pcGlyphs)
1435 INT nextIndex;
1436 INT prevCount = *pcGlyphs;
1437 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1438 if (nextIndex > GSUB_E_NOGLYPH)
1440 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1441 i = nextIndex;
1443 else
1444 i++;
1446 return *pcGlyphs;
1448 return GSUB_E_NOFEATURE;
1451 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1453 if (i + delta < 0)
1454 return 0;
1455 if ( i+ delta >= cchLen)
1456 return 0;
1458 i += delta;
1460 return chars[i];
1463 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1465 if (i + delta < 0)
1467 if (psa->fLinkBefore)
1468 return jtR;
1469 else
1470 return jtU;
1472 if ( i+ delta >= cchLen)
1474 if (psa->fLinkAfter)
1475 return jtL;
1476 else
1477 return jtU;
1480 i += delta;
1482 if (context_type[i] == jtT)
1483 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1484 else
1485 return context_type[i];
1488 static inline BOOL right_join_causing(CHAR joining_type)
1490 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1493 static inline BOOL left_join_causing(CHAR joining_type)
1495 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1498 static inline BOOL word_break_causing(WCHAR chr)
1500 /* we are working within a string of characters already guareented to
1501 be within one script, Syriac, so we do not worry about any characers
1502 other than the space character outside of that range */
1503 return (chr == 0 || chr == 0x20 );
1507 * ContextualShape_Arabic
1509 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1511 CHAR *context_type;
1512 INT *context_shape;
1513 INT dirR, dirL;
1514 int i;
1516 if (*pcGlyphs != cChars)
1518 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1519 return;
1522 if (!psa->fLogicalOrder && psa->fRTL)
1524 dirR = 1;
1525 dirL = -1;
1527 else
1529 dirR = -1;
1530 dirL = 1;
1533 if (!psc->GSUB_Table)
1534 psc->GSUB_Table = load_gsub_table(hdc);
1536 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1537 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1539 for (i = 0; i < cChars; i++)
1540 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1542 for (i = 0; i < cChars; i++)
1544 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1545 context_shape[i] = Xr;
1546 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1547 context_shape[i] = Xl;
1548 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)))
1549 context_shape[i] = Xm;
1550 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1551 context_shape[i] = Xr;
1552 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1553 context_shape[i] = Xl;
1554 else
1555 context_shape[i] = Xn;
1558 /* Contextual Shaping */
1559 i = 0;
1560 while(i < *pcGlyphs)
1562 BOOL shaped = FALSE;
1564 if (psc->GSUB_Table)
1566 INT nextIndex;
1567 INT prevCount = *pcGlyphs;
1568 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1569 if (nextIndex > GSUB_E_NOGLYPH)
1571 i = nextIndex;
1572 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1574 shaped = (nextIndex > GSUB_E_NOGLYPH);
1577 if (!shaped)
1579 WORD newGlyph = pwOutGlyphs[i];
1580 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1582 /* fall back to presentation form B */
1583 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1584 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1585 pwOutGlyphs[i] = newGlyph;
1587 i++;
1591 HeapFree(GetProcessHeap(),0,context_shape);
1592 HeapFree(GetProcessHeap(),0,context_type);
1596 * ContextualShape_Syriac
1599 #define ALAPH 0x710
1600 #define DALATH 0x715
1601 #define RISH 0x72A
1603 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1605 CHAR *context_type;
1606 INT *context_shape;
1607 INT dirR, dirL;
1608 int i;
1610 if (*pcGlyphs != cChars)
1612 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1613 return;
1616 if (!psa->fLogicalOrder && psa->fRTL)
1618 dirR = 1;
1619 dirL = -1;
1621 else
1623 dirR = -1;
1624 dirL = 1;
1627 if (!psc->GSUB_Table)
1628 psc->GSUB_Table = load_gsub_table(hdc);
1630 if (!psc->GSUB_Table)
1631 return;
1633 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1634 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1636 for (i = 0; i < cChars; i++)
1637 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1639 for (i = 0; i < cChars; i++)
1641 if (pwcChars[i] == ALAPH)
1643 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1645 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1646 context_shape[i] = Afj;
1647 else if ( rchar != DALATH && rchar != RISH &&
1648 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1649 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1650 context_shape[i] = Afn;
1651 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1652 context_shape[i] = Afx;
1653 else
1654 context_shape[i] = Xn;
1656 else if (context_type[i] == jtR &&
1657 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1658 context_shape[i] = Xr;
1659 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1660 context_shape[i] = Xl;
1661 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)))
1662 context_shape[i] = Xm;
1663 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1664 context_shape[i] = Xr;
1665 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1666 context_shape[i] = Xl;
1667 else
1668 context_shape[i] = Xn;
1671 /* Contextual Shaping */
1672 i = 0;
1673 while(i < *pcGlyphs)
1675 INT nextIndex;
1676 INT prevCount = *pcGlyphs;
1677 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1678 if (nextIndex > GSUB_E_NOGLYPH)
1680 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1681 i = nextIndex;
1683 else
1684 i++;
1687 HeapFree(GetProcessHeap(),0,context_shape);
1688 HeapFree(GetProcessHeap(),0,context_type);
1692 * ContextualShape_Phags_pa
1695 #define phags_pa_CANDRABINDU 0xA873
1696 #define phags_pa_START 0xA840
1697 #define phags_pa_END 0xA87F
1699 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1701 INT *context_shape;
1702 INT dirR, dirL;
1703 int i;
1705 if (*pcGlyphs != cChars)
1707 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1708 return;
1711 if (!psa->fLogicalOrder && psa->fRTL)
1713 dirR = 1;
1714 dirL = -1;
1716 else
1718 dirR = -1;
1719 dirL = 1;
1722 if (!psc->GSUB_Table)
1723 psc->GSUB_Table = load_gsub_table(hdc);
1725 if (!psc->GSUB_Table)
1726 return;
1728 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1730 for (i = 0; i < cChars; i++)
1732 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1734 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1735 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1736 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1737 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1739 if (jrchar && jlchar)
1740 context_shape[i] = Xm;
1741 else if (jrchar)
1742 context_shape[i] = Xr;
1743 else if (jlchar)
1744 context_shape[i] = Xl;
1745 else
1746 context_shape[i] = Xn;
1748 else
1749 context_shape[i] = -1;
1752 /* Contextual Shaping */
1753 i = 0;
1754 while(i < *pcGlyphs)
1756 if (context_shape[i] >= 0)
1758 INT nextIndex;
1759 INT prevCount = *pcGlyphs;
1760 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1761 if (nextIndex > GSUB_E_NOGLYPH)
1763 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1764 i = nextIndex;
1766 else
1767 i++;
1769 else
1770 i++;
1773 HeapFree(GetProcessHeap(),0,context_shape);
1776 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1778 int i;
1780 /* Replace */
1781 pwOutChars[cWalk] = replacements[0];
1782 cWalk=cWalk+1;
1784 /* Insert */
1785 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1787 int j;
1788 for (j = *pcChars; j > cWalk; j--)
1789 pwOutChars[j] = pwOutChars[j-1];
1790 *pcChars= *pcChars+1;
1791 pwOutChars[cWalk] = replacements[i];
1792 cWalk = cWalk+1;
1796 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1798 int i;
1799 int cWalk;
1801 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1803 for (i = 0; vowels[i].base != 0x0; i++)
1805 if (pwOutChars[cWalk] == vowels[i].base)
1807 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1808 break;
1814 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1816 int i;
1817 int cWalk;
1819 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1821 for (i = 0; consonants[i].output!= 0x0; i++)
1823 int j;
1824 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1825 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1826 break;
1828 if (consonants[i].parts[j]==0x0) /* matched all */
1830 int k;
1831 j--;
1832 pwOutChars[cWalk] = consonants[i].output;
1833 for(k = cWalk+1; k < *pcChars - j; k++)
1834 pwOutChars[k] = pwOutChars[k+j];
1835 *pcChars = *pcChars - j;
1836 break;
1839 cWalk++;
1843 static void Reorder_Ra_follows_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1845 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1847 int j;
1848 WORD Ra = pwChar[start];
1849 WORD H = pwChar[start+1];
1851 TRACE("Doing reorder of Ra to %i\n",main);
1852 for (j = start; j < main-1; j++)
1853 pwChar[j] = pwChar[j+2];
1854 pwChar[main-1] = Ra;
1855 pwChar[main] = H;
1859 static void Reorder_Ra_follows_matra_post(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1861 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1863 int j,loc;
1864 WORD Ra = pwChar[start];
1865 WORD H = pwChar[start+1];
1866 for (loc = main; loc > end; loc++)
1867 if (lexical(pwChar[loc]) == lex_Matra_post)
1868 break;
1869 if (loc == end) loc = main;
1871 TRACE("Doing reorder of Ra to %i\n",loc);
1872 for (j = start; j < loc-1; j++)
1873 pwChar[j] = pwChar[j+2];
1874 pwChar[loc-1] = Ra;
1875 pwChar[loc] = H;
1879 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1881 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1883 int j;
1884 WORD Ra = pwChar[start];
1885 WORD H = pwChar[start+1];
1887 TRACE("Doing reorder of Ra to %i\n",end-1);
1888 for (j = start; j < end-1; j++)
1889 pwChar[j] = pwChar[j+2];
1890 pwChar[end-1] = Ra;
1891 pwChar[end] = H;
1895 static void Reorder_Matra_precede_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1897 int i;
1899 /* reorder Matras */
1900 if (end > main)
1902 for (i = 1; i <= end-main; i++)
1904 if (lexical(pwChar[main+i]) == lex_Matra_pre)
1906 int j;
1907 WCHAR c = pwChar[main+i];
1908 TRACE("Doing reorder of %x %x\n",c,pwChar[main]);
1909 for (j = main+i; j > main; j--)
1910 pwChar[j] = pwChar[j-1];
1911 pwChar[main] = c;
1917 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1919 int i;
1921 /* reorder Matras */
1922 if (end > main)
1924 for (i = 1; i <= end-main; i++)
1926 if (lexical(pwChar[main+i]) == lex_Matra_pre)
1928 int j;
1929 WCHAR c = pwChar[main+i];
1930 TRACE("Doing reorder of %x to %i\n",c,start);
1931 for (j = main+i; j > start; j--)
1932 pwChar[j] = pwChar[j-1];
1933 pwChar[start] = c;
1939 static void Reorder_Like_Sinhala(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1941 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1942 if (start == main && main == end) return;
1944 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1945 if (lexical(pwChar[main]) == lex_Vowel) return;
1947 Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1948 Reorder_Matra_precede_base(pwChar, start, main, end, lexical);
1951 static void Reorder_Like_Devanagari(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1953 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1954 if (start == main && main == end) return;
1956 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1957 if (lexical(pwChar[main]) == lex_Vowel) return;
1959 Reorder_Ra_follows_matra_post(pwChar, start, main, end, lexical);
1960 Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1963 static void Reorder_Like_Bengali(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1965 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1966 if (start == main && main == end) return;
1968 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1969 if (lexical(pwChar[main]) == lex_Vowel) return;
1971 Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1972 Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1975 static void Reorder_Like_Kannada(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1977 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1978 if (start == main && main == end) return;
1980 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1981 if (lexical(pwChar[main]) == lex_Vowel) return;
1983 Reorder_Ra_follows_syllable(pwChar, start, main, end, lexical);
1984 Reorder_Matra_precede_syllable(pwChar, start, main, end, lexical);
1987 static void Reorder_Like_Malayalam(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1989 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1990 if (start == main && main == end) return;
1992 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1993 if (lexical(pwChar[main]) == lex_Vowel) return;
1995 Reorder_Ra_follows_matra_post(pwChar, start, main, end, lexical);
1996 Reorder_Matra_precede_base(pwChar, start, main, end, lexical);
1999 static int sinhala_lex(WCHAR c)
2001 switch (c)
2003 case 0x0DCA: return lex_Halant;
2004 case 0x0DCF:
2005 case 0x0DDF:
2006 case 0x0DD8: return lex_Matra_post;
2007 case 0x0DD9:
2008 case 0x0DDB: return lex_Matra_pre;
2009 case 0x0DDA:
2010 case 0x0DDC: return lex_Composed_Vowel;
2011 case 0x200D: return lex_ZWJ;
2012 case 0x200C: return lex_ZWNJ;
2013 case 0x00A0: return lex_NBSP;
2014 default:
2015 if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
2016 else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
2017 else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
2018 else if (c>=0x0DD0 && c <=0x0DD1) return lex_Matra_post;
2019 else if (c>=0x0DD2 && c <=0x0DD3) return lex_Matra_above;
2020 else if (c>=0x0DD4 && c <=0x0DD6) return lex_Matra_below;
2021 else if (c>=0x0DDD && c <=0x0DDE) return lex_Composed_Vowel;
2022 else if (c>=0x0DF2 && c <=0x0DF3) return lex_Matra_post;
2023 else return lex_Generic;
2027 static const VowelComponents Sinhala_vowels[] = {
2028 {0x0DDA, {0x0DD9,0x0DCA,0x0}},
2029 {0x0DDC, {0x0DD9,0x0DCF,0x0}},
2030 {0x0DDD, {0x0DD9,0x0DCF,0x0DCA}},
2031 {0x0DDE, {0x0DD9,0x0DDF,0x0}},
2032 {0x0000, {0x0000,0x0000,0x0}}};
2034 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2036 int cCount = cChars;
2037 WCHAR *input;
2039 if (*pcGlyphs != cChars)
2041 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2042 return;
2045 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2047 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2049 /* Step 1: Decompose multi part vowels */
2050 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels);
2052 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2054 /* Step 2: Reorder within Syllables */
2055 Indic_ReorderCharacters( input, cCount, sinhala_lex, Reorder_Like_Sinhala);
2056 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2058 /* Step 3: Get glyphs */
2059 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2060 *pcGlyphs = cCount;
2062 HeapFree(GetProcessHeap(),0,input);
2065 static int devanagari_lex(WCHAR c)
2067 switch (c)
2069 case 0x0951:
2070 case 0x0952:
2071 case 0x0903: return lex_Modifier;
2072 case 0x0930: return lex_Ra;
2073 case 0x093C: return lex_Nukta;
2074 case 0x0940:
2075 case 0x093E: return lex_Matra_post;
2076 case 0x093F: return lex_Matra_pre;
2077 case 0x094D: return lex_Halant;
2078 case 0x0972: return lex_Vowel;
2079 case 0x200C: return lex_ZWNJ;
2080 case 0x200D: return lex_ZWJ;
2081 default:
2082 if (c>=0x0901 && c<=0x0902) return lex_Matra_above;
2083 else if (c>=0x0904 && c<=0x0914) return lex_Vowel;
2084 else if (c>=0x0915 && c<=0x0939) return lex_Consonant;
2085 else if (c>=0x0941 && c<=0x0944) return lex_Matra_below;
2086 else if (c>=0x0945 && c<=0x0948) return lex_Matra_above;
2087 else if (c>=0x0949 && c<=0x094C) return lex_Matra_post;
2088 else if (c>=0x0953 && c<=0x0954) return lex_Modifier;
2089 else if (c>=0x0958 && c<=0x095F) return lex_Consonant;
2090 else if (c>=0x0960 && c<=0x0961) return lex_Vowel;
2091 else if (c>=0x0962 && c<=0x0963) return lex_Matra_below;
2092 else if (c>=0x097B && c<=0x097C) return lex_Consonant;
2093 else if (c>=0x097E && c<=0x097F) return lex_Consonant;
2094 else return lex_Generic;
2098 static const ConsonantComponents Devanagari_consonants[] ={
2099 {{0x0928, 0x093C, 0x00000}, 0x0929},
2100 {{0x0930, 0x093C, 0x00000}, 0x0931},
2101 {{0x0933, 0x093C, 0x00000}, 0x0934},
2102 {{0x0915, 0x093C, 0x00000}, 0x0958},
2103 {{0x0916, 0x093C, 0x00000}, 0x0959},
2104 {{0x0917, 0x093C, 0x00000}, 0x095A},
2105 {{0x091C, 0x093C, 0x00000}, 0x095B},
2106 {{0x0921, 0x093C, 0x00000}, 0x095C},
2107 {{0x0922, 0x093C, 0x00000}, 0x095D},
2108 {{0x092B, 0x093C, 0x00000}, 0x095E},
2109 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2111 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2113 int cCount = cChars;
2114 WCHAR *input;
2116 if (*pcGlyphs != cChars)
2118 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2119 return;
2122 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2123 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2125 /* Step 1: Compose Consonant and Nukta */
2126 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2127 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2129 /* Step 2: Reorder within Syllables */
2130 Indic_ReorderCharacters( input, cCount, devanagari_lex, Reorder_Like_Devanagari);
2131 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2132 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2133 *pcGlyphs = cCount;
2135 HeapFree(GetProcessHeap(),0,input);
2138 static int bengali_lex(WCHAR c)
2140 switch (c)
2142 case 0x0981: return lex_Modifier;
2143 case 0x09AC:
2144 case 0x09AF:
2145 case 0x09CE: return lex_Consonant;
2146 case 0x09B0: return lex_Ra;
2147 case 0x09BC: return lex_Nukta;
2148 case 0x09BF: return lex_Matra_pre;
2149 case 0x09D7:
2150 case 0x09BE:
2151 case 0x09C0: return lex_Matra_post;
2152 case 0x09CD: return lex_Halant;
2153 case 0x200C: return lex_ZWNJ;
2154 case 0x200D: return lex_ZWJ;
2155 default:
2156 if (c>=0x0982 && c<=0x0983) return lex_Matra_post;
2157 else if (c>=0x0985 && c<=0x0994) return lex_Vowel;
2158 else if (c>=0x0995 && c<=0x09B9) return lex_Consonant;
2159 else if (c>=0x09C1 && c<=0x09C4) return lex_Matra_below;
2160 else if (c>=0x09C7 && c<=0x09C8) return lex_Matra_pre;
2161 else if (c>=0x09DC && c<=0x09DF) return lex_Consonant;
2162 else if (c>=0x09E0 && c<=0x09E1) return lex_Vowel;
2163 else if (c>=0x09E2 && c<=0x09E3) return lex_Matra_below;
2164 else if (c>=0x09F0 && c<=0x09F1) return lex_Consonant;
2165 else return lex_Generic;
2169 static const VowelComponents Bengali_vowels[] = {
2170 {0x09CB, {0x09C7,0x09BE,0x0000}},
2171 {0x09CC, {0x09C7,0x09D7,0x0000}},
2172 {0x0000, {0x0000,0x0000,0x0000}}};
2174 static const ConsonantComponents Bengali_consonants[] = {
2175 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2176 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2177 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2178 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2179 {{0x0000,0x0000,0x0000}, 0x0000}};
2181 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2183 int cCount = cChars;
2184 WCHAR *input;
2186 if (*pcGlyphs != cChars)
2188 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2189 return;
2192 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2193 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2195 /* Step 1: Decompose Vowels and Compose Consonents */
2196 DecomposeVowels(hdc, input, &cCount, Bengali_vowels);
2197 ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2198 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2200 /* Step 2: Reorder within Syllables */
2201 Indic_ReorderCharacters( input, cCount, bengali_lex, Reorder_Like_Bengali);
2202 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2203 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2204 *pcGlyphs = cCount;
2206 HeapFree(GetProcessHeap(),0,input);
2209 static int gurmukhi_lex(WCHAR c)
2211 switch (c)
2213 case 0x0A30:
2214 case 0x0A35:
2215 case 0x0A39:
2216 case 0x0A2f: return lex_Consonant;
2217 case 0x0A3C: return lex_Nukta;
2218 case 0x0A3F: return lex_Matra_pre;
2219 case 0x0A03:
2220 case 0x0A3E:
2221 case 0x0A40: return lex_Matra_post;
2222 case 0x0A4D: return lex_Halant;
2223 case 0x0A70:
2224 case 0x0A71: return lex_Modifier;
2225 case 0x200C: return lex_ZWNJ;
2226 case 0x200D: return lex_ZWJ;
2227 default:
2228 if (c>=0x0A01 && c<=0x0A02) return lex_Modifier;
2229 else if (c>=0x0A05 && c<=0x0A14) return lex_Vowel;
2230 else if (c>=0x0A15 && c<=0x0A38) return lex_Consonant;
2231 else if (c>=0x0A41 && c<=0x0A42) return lex_Matra_below;
2232 else if (c>=0x0A47 && c<=0x0A4C) return lex_Matra_above;
2233 else if (c>=0x0A59 && c<=0x0A5E) return lex_Consonant;
2234 else return lex_Generic;
2238 static const ConsonantComponents Gurmukhi_consonants[] = {
2239 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2240 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2241 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2242 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2243 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2244 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2245 {{0x0000,0x0000,0x0000}, 0x0000}};
2247 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2249 int cCount = cChars;
2250 WCHAR *input;
2252 if (*pcGlyphs != cChars)
2254 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2255 return;
2258 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2259 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2261 /* Step 1: Compose Consonents */
2262 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2263 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2265 /* Step 2: Reorder within Syllables */
2266 Indic_ReorderCharacters( input, cCount, gurmukhi_lex, Reorder_Like_Bengali);
2267 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2268 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2269 *pcGlyphs = cCount;
2271 HeapFree(GetProcessHeap(),0,input);
2274 static int gujarati_lex(WCHAR c)
2276 switch (c)
2278 case 0x0A83: return lex_Modifier;
2279 case 0x0AB0: return lex_Ra;
2280 case 0x0ABC: return lex_Nukta;
2281 case 0x0ABF: return lex_Matra_pre;
2282 case 0x0ABE:
2283 case 0x0AC0: return lex_Matra_post;
2284 case 0x0ACD: return lex_Halant;
2285 case 0x200C: return lex_ZWNJ;
2286 case 0x200D: return lex_ZWJ;
2287 default:
2288 if (c>=0x0A81 && c<=0x0A82) return lex_Modifier;
2289 else if (c>=0x0A85 && c<=0x0A94) return lex_Vowel;
2290 else if (c>=0x0A95 && c<=0x0AB9) return lex_Consonant;
2291 else if (c>=0x0AC1 && c<=0x0AC4) return lex_Matra_below;
2292 else if (c>=0x0AC5 && c<=0x0AC8) return lex_Matra_above;
2293 else if (c>=0x0AC9 && c<=0x0ACC) return lex_Matra_post;
2294 else if (c>=0x0AE0 && c<=0x0AE1) return lex_Vowel;
2295 else if (c>=0x0AE2 && c<=0x0AE3) return lex_Matra_below;
2296 else return lex_Generic;
2300 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2302 int cCount = cChars;
2303 WCHAR *input;
2305 if (*pcGlyphs != cChars)
2307 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2308 return;
2311 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2312 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2314 /* Step 1: Reorder within Syllables */
2315 Indic_ReorderCharacters( input, cCount, gujarati_lex, Reorder_Like_Devanagari);
2316 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2317 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2318 *pcGlyphs = cCount;
2320 HeapFree(GetProcessHeap(),0,input);
2323 static int oriya_lex(WCHAR c)
2325 switch (c)
2327 case 0x0B24:
2328 case 0x0B28:
2329 case 0x0B2F:
2330 case 0x0B5F:
2331 case 0x0B71:
2332 case 0x0B33: return lex_Consonant;
2333 case 0x0B30: return lex_Ra;
2334 case 0x0B3C: return lex_Nukta;
2335 case 0x0B3F:
2336 case 0x0B56: return lex_Matra_above;
2337 case 0x0B3E:
2338 case 0x0B57:
2339 case 0x0B40: return lex_Matra_post;
2340 case 0x0B47: return lex_Matra_pre;
2341 case 0x0B4D: return lex_Halant;
2342 case 0x200C: return lex_ZWNJ;
2343 case 0x200D: return lex_ZWJ;
2344 default:
2345 if (c>=0x0B01 && c<=0x0B03) return lex_Modifier;
2346 else if (c>=0x0B05 && c<=0x0B14) return lex_Vowel;
2347 else if (c>=0x0B15 && c<=0x0B39) return lex_Consonant;
2348 else if (c>=0x0B2C && c<=0x0B2E) return lex_Consonant;
2349 else if (c>=0x0B32 && c<=0x0B33) return lex_Consonant;
2350 else if (c>=0x0B41 && c<=0x0B44) return lex_Matra_below;
2351 else if (c>=0x0B48 && c<=0x0B4C) return lex_Composed_Vowel;
2352 else if (c>=0x0B5C && c<=0x0B5D) return lex_Consonant;
2353 else if (c>=0x0B60 && c<=0x0B61) return lex_Vowel;
2354 else if (c>=0x0B62 && c<=0x0B63) return lex_Matra_below;
2355 else return lex_Generic;
2359 static const VowelComponents Oriya_vowels[] = {
2360 {0x0B48, {0x0B47,0x0B56,0x0000}},
2361 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2362 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2363 {0x0000, {0x0000,0x0000,0x0000}}};
2365 static const ConsonantComponents Oriya_consonants[] = {
2366 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2367 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2368 {{0x0000,0x0000,0x0000}, 0x0000}};
2370 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2372 int cCount = cChars;
2373 WCHAR *input;
2375 if (*pcGlyphs != cChars)
2377 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2378 return;
2381 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2382 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2384 /* Step 1: Decompose Vowels and Compose Consonents */
2385 DecomposeVowels(hdc, input, &cCount, Oriya_vowels);
2386 ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2387 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2389 /* Step 2: Reorder within Syllables */
2390 Indic_ReorderCharacters( input, cCount, oriya_lex, Reorder_Like_Bengali);
2391 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2392 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2393 *pcGlyphs = cCount;
2395 HeapFree(GetProcessHeap(),0,input);
2398 static int tamil_lex(WCHAR c)
2400 switch (c)
2402 case 0x0BC0: return lex_Matra_above;
2403 case 0x0BCD: return lex_Halant;
2404 case 0x0BD7: return lex_Matra_post;
2405 case 0x200C: return lex_ZWNJ;
2406 case 0x200D: return lex_ZWJ;
2407 default:
2408 if (c>=0x0B95 && c<=0x0BB9) return lex_Consonant;
2409 else if (c>=0x0BBE && c<=0x0BBF) return lex_Matra_post;
2410 else if (c>=0x0BC1 && c<=0x0BC2) return lex_Matra_below;
2411 else if (c>=0x0BC6 && c<=0x0BC8) return lex_Matra_pre;
2412 else return lex_Generic;
2416 static const VowelComponents Tamil_vowels[] = {
2417 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2418 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2419 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2420 {0x0000, {0x0000,0x0000,0x0000}}};
2422 static const ConsonantComponents Tamil_consonants[] = {
2423 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2424 {{0x0000,0x0000,0x0000}, 0x0000}};
2426 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2428 int cCount = cChars;
2429 WCHAR *input;
2431 if (*pcGlyphs != cChars)
2433 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2434 return;
2437 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2438 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2440 /* Step 1: Decompose Vowels and Compose Consonents */
2441 DecomposeVowels(hdc, input, &cCount, Tamil_vowels);
2442 ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2443 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2445 /* Step 2: Reorder within Syllables */
2446 Indic_ReorderCharacters( input, cCount, tamil_lex, Reorder_Like_Sinhala);
2447 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2448 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2449 *pcGlyphs = cCount;
2451 HeapFree(GetProcessHeap(),0,input);
2454 static int telugu_lex(WCHAR c)
2456 switch (c)
2458 case 0x0C4D: return lex_Halant;
2459 case 0x0C55: return lex_Matra_above;
2460 case 0x0C56: return lex_Matra_below;
2461 case 0x200C: return lex_ZWNJ;
2462 case 0x200D: return lex_ZWJ;
2463 default:
2464 if (c>=0x0C01 && c<=0x0C03) return lex_Matra_post;
2465 else if (c>=0x0C05 && c<=0x0C14) return lex_Vowel;
2466 else if (c>=0x0C15 && c<=0x0C39) return lex_Consonant;
2467 else if (c>=0x0C3E && c<=0x0C40) return lex_Matra_above;
2468 else if (c>=0x0C41 && c<=0x0C44) return lex_Matra_post;
2469 else if (c>=0x0C46 && c<=0x0C47) return lex_Matra_above;
2470 else if (c>=0x0C4A && c<=0x0C4C) return lex_Matra_above;
2471 else if (c>=0x0C58 && c<=0x0C59) return lex_Consonant;
2472 else if (c>=0x0C60 && c<=0x0C61) return lex_Vowel;
2473 else if (c>=0x0C62 && c<=0x0C63) return lex_Matra_below;
2474 else return lex_Generic;
2478 static const VowelComponents Telugu_vowels[] = {
2479 {0x0C48, {0x0C46,0x0C56,0x0000}},
2480 {0x0000, {0x0000,0x0000,0x0000}}};
2482 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2484 int cCount = cChars;
2485 WCHAR *input;
2487 if (*pcGlyphs != cChars)
2489 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2490 return;
2493 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2494 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2496 /* Step 1: Decompose Vowels */
2497 DecomposeVowels(hdc, input, &cCount, Telugu_vowels);
2498 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2500 /* Step 2: Reorder within Syllables */
2501 Indic_ReorderCharacters( input, cCount, telugu_lex, Reorder_Like_Bengali);
2502 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2503 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2504 *pcGlyphs = cCount;
2506 HeapFree(GetProcessHeap(),0,input);
2509 static int kannada_lex(WCHAR c)
2511 switch (c)
2513 case 0x0CB0: return lex_Ra;
2514 case 0x0CBC: return lex_Nukta;
2515 case 0x0CBE: return lex_Matra_post;
2516 case 0x0CBF: return lex_Matra_above;
2517 case 0x0CC6: return lex_Matra_above;
2518 case 0x0CCC: return lex_Matra_above;
2519 case 0x0CCD: return lex_Halant;
2520 case 0x0CCE: return lex_Consonant;
2521 case 0x200C: return lex_ZWNJ;
2522 case 0x200D: return lex_ZWJ;
2523 default:
2524 if (c>=0x0C82 && c<=0x0C83) return lex_Modifier;
2525 else if (c>=0x0C85 && c<=0x0C94) return lex_Vowel;
2526 else if (c>=0x0C95 && c<=0x0CB9) return lex_Consonant;
2527 else if (c>=0x0CC1 && c<=0x0CC4) return lex_Matra_post;
2528 else if (c>=0x0CD5 && c<=0x0CD6) return lex_Modifier;
2529 else if (c>=0x0CE0 && c<=0x0CE1) return lex_Vowel;
2530 else if (c>=0x0CE2 && c<=0x0CE3) return lex_Matra_below;
2531 else return lex_Generic;
2535 static const VowelComponents Kannada_vowels[] = {
2536 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2537 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2538 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2539 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2540 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2541 {0x0000, {0x0000,0x0000,0x0000}}};
2543 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2545 int cCount = cChars;
2546 WCHAR *input;
2548 if (*pcGlyphs != cChars)
2550 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2551 return;
2554 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2555 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2557 /* Step 1: Decompose Vowels */
2558 DecomposeVowels(hdc, input, &cCount, Kannada_vowels);
2559 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2561 /* Step 2: Reorder within Syllables */
2562 Indic_ReorderCharacters( input, cCount, kannada_lex, Reorder_Like_Kannada);
2563 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2564 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2565 *pcGlyphs = cCount;
2567 HeapFree(GetProcessHeap(),0,input);
2570 static int malayalam_lex(WCHAR c)
2572 switch (c)
2574 case 0x0D35: return lex_Consonant;
2575 case 0x0D4D: return lex_Halant;
2576 case 0x0D57: return lex_Matra_post;
2577 case 0x200C: return lex_ZWNJ;
2578 case 0x200D: return lex_ZWJ;
2579 default:
2580 if (c>=0x0D02 && c<=0x0D03) return lex_Modifier;
2581 else if (c>=0x0D05 && c<=0x0D14) return lex_Vowel;
2582 else if (c>=0x0D15 && c<=0x0D39) return lex_Consonant;
2583 else if (c>=0x0D3E && c<=0x0D44) return lex_Matra_post;
2584 else if (c>=0x0D46 && c<=0x0D48) return lex_Matra_pre;
2585 else if (c>=0x0D60 && c<=0x0D61) return lex_Vowel;
2586 else if (c>=0x0D62 && c<=0x0D63) return lex_Matra_below;
2587 else return lex_Generic;
2591 static const VowelComponents Malayalam_vowels[] = {
2592 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2593 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2594 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2595 {0x0000, {0x0000,0x0000,0x0000}}};
2597 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2599 int cCount = cChars;
2600 WCHAR *input;
2602 if (*pcGlyphs != cChars)
2604 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2605 return;
2608 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2609 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2611 /* Step 1: Decompose Vowels */
2612 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels);
2613 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2615 /* Step 2: Reorder within Syllables */
2616 Indic_ReorderCharacters( input, cCount, malayalam_lex, Reorder_Like_Malayalam);
2617 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2618 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2619 *pcGlyphs = cCount;
2621 HeapFree(GetProcessHeap(),0,input);
2624 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)
2626 int i,k;
2628 for (i = 0; i < cGlyphs; i++)
2630 int char_index[20];
2631 int char_count = 0;
2633 for (k = 0; k < cChars; k++)
2635 if (pwLogClust[k] == i)
2637 char_index[char_count] = k;
2638 char_count++;
2642 if (char_count == 0)
2644 FIXME("No chars in this glyph? Must be an error\n");
2645 continue;
2648 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2650 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2651 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2653 else
2654 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2657 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2658 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2661 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 )
2663 int i,k;
2664 int initGlyph, finaGlyph;
2665 INT dirR, dirL;
2666 BYTE *spaces;
2668 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2669 memset(spaces,0,cGlyphs);
2671 if (!psa->fLogicalOrder && psa->fRTL)
2673 initGlyph = cGlyphs-1;
2674 finaGlyph = 0;
2675 dirR = 1;
2676 dirL = -1;
2678 else
2680 initGlyph = 0;
2681 finaGlyph = cGlyphs-1;
2682 dirR = -1;
2683 dirL = 1;
2686 for (i = 0; i < cGlyphs; i++)
2688 for (k = 0; k < cChars; k++)
2689 if (pwLogClust[k] == i)
2691 if (pwcChars[k] == 0x0020)
2692 spaces[i] = 1;
2696 for (i = 0; i < cGlyphs; i++)
2698 int char_index[20];
2699 int char_count = 0;
2700 BOOL isInit, isFinal;
2702 for (k = 0; k < cChars; k++)
2704 if (pwLogClust[k] == i)
2706 char_index[char_count] = k;
2707 char_count++;
2711 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2712 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2714 if (char_count == 0)
2716 FIXME("No chars in this glyph? Must be an error\n");
2717 continue;
2720 if (char_count == 1)
2722 if (pwcChars[char_index[0]] == 0x0020) /* space */
2724 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2725 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2727 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2728 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2729 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2731 if (!isInit && !isFinal)
2732 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2733 else if (isInit)
2734 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2735 else
2736 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2738 else if (!isInit)
2740 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2741 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2742 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2743 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2744 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2745 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2746 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2747 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2748 else
2749 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2751 else if (!isInit && !isFinal)
2752 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2753 else
2754 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2756 else if (char_count == 2)
2758 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2759 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2760 else if (!isInit)
2761 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2762 else
2763 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2765 else if (!isInit && !isFinal)
2766 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2767 else
2768 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2771 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2772 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2773 HeapFree(GetProcessHeap(),0,spaces);
2776 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 )
2778 int i,k;
2779 int finaGlyph;
2780 INT dirL;
2781 BYTE *spaces;
2783 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2784 memset(spaces,0,cGlyphs);
2786 if (!psa->fLogicalOrder && psa->fRTL)
2788 finaGlyph = 0;
2789 dirL = -1;
2791 else
2793 finaGlyph = cGlyphs-1;
2794 dirL = 1;
2797 for (i = 0; i < cGlyphs; i++)
2799 for (k = 0; k < cChars; k++)
2800 if (pwLogClust[k] == i)
2802 if (pwcChars[k] == 0x0020)
2803 spaces[i] = 1;
2807 for (i = 0; i < cGlyphs; i++)
2809 int char_index[20];
2810 int char_count = 0;
2812 for (k = 0; k < cChars; k++)
2814 if (pwLogClust[k] == i)
2816 char_index[char_count] = k;
2817 char_count++;
2821 if (char_count == 0)
2823 FIXME("No chars in this glyph? Must be an error\n");
2824 continue;
2827 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2829 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2830 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2832 else if (i == finaGlyph)
2833 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2834 else
2835 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2838 HeapFree(GetProcessHeap(),0,spaces);
2839 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2840 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2842 /* Do not allow justification between marks and their base */
2843 for (i = 0; i < cGlyphs; i++)
2845 if (!pGlyphProp[i].sva.fClusterStart)
2846 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2850 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)
2852 int i,k;
2854 for (i = 0; i < cGlyphs; i++)
2856 int char_index[20];
2857 int char_count = 0;
2859 for (k = 0; k < cChars; k++)
2861 if (pwLogClust[k] == i)
2863 char_index[char_count] = k;
2864 char_count++;
2868 if (char_count == 0)
2870 FIXME("No chars in this glyph? Must be an error\n");
2871 continue;
2874 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2876 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2877 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2879 else
2880 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2882 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2883 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2886 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)
2888 int i,k;
2890 for (i = 0; i < cGlyphs; i++)
2892 int char_index[20];
2893 int char_count = 0;
2895 for (k = 0; k < cChars; k++)
2897 if (pwLogClust[k] == i)
2899 char_index[char_count] = k;
2900 char_count++;
2904 if (char_count == 0)
2906 FIXME("No chars in this glyph? Must be an error\n");
2907 continue;
2910 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2912 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2913 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2915 else
2916 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2918 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2919 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2921 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2922 for (i = 0; i < cGlyphs; i++)
2924 if (!pGlyphProp[i].sva.fClusterStart)
2926 pGlyphProp[i].sva.fDiacritic = 0;
2927 pGlyphProp[i].sva.fZeroWidth = 0;
2932 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)
2934 int i,k;
2936 for (i = 0; i < cGlyphs; i++)
2938 int char_index[20];
2939 int char_count = 0;
2941 for (k = 0; k < cChars; k++)
2943 if (pwLogClust[k] == i)
2945 char_index[char_count] = k;
2946 char_count++;
2950 if (char_count == 0)
2952 FIXME("No chars in this glyph? Must be an error\n");
2953 continue;
2956 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2958 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2959 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2961 else
2962 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2964 pGlyphProp[i].sva.fClusterStart = 0;
2965 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2966 switch (lexical(pwcChars[char_index[k]]))
2968 case lex_Matra_pre:
2969 case lex_Matra_post:
2970 case lex_Matra_above:
2971 case lex_Matra_below:
2972 case lex_Modifier:
2973 break;
2974 default:
2975 pGlyphProp[i].sva.fClusterStart = 1;
2976 break;
2979 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2982 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 )
2984 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
2987 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 )
2989 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
2992 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 )
2994 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
2997 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 )
2999 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3002 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 )
3004 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3007 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 )
3009 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3012 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 )
3014 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3017 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 )
3019 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3022 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 )
3024 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3027 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)
3029 if (ShapingData[psa->eScript].charGlyphPropProc)
3030 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3031 else
3032 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3035 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3037 if (ShapingData[psa->eScript].contextProc)
3038 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3041 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)
3043 int i;
3044 INT dirL;
3046 if (!rpRangeProperties)
3047 return;
3049 if (!psc->GSUB_Table)
3050 psc->GSUB_Table = load_gsub_table(hdc);
3052 if (!psc->GSUB_Table)
3053 return;
3055 if (!psa->fLogicalOrder && psa->fRTL)
3056 dirL = -1;
3057 else
3058 dirL = 1;
3060 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3062 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3063 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3067 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3069 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3070 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3072 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3075 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3077 const GSUB_Feature *feature;
3078 int i;
3080 if (!ShapingData[psa->eScript].requiredFeatures)
3081 return S_OK;
3083 if (!psc->GSUB_Table)
3084 psc->GSUB_Table = load_gsub_table(hdc);
3086 /* we need to have at least one of the required features */
3087 i = 0;
3088 while (ShapingData[psa->eScript].requiredFeatures[i])
3090 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3091 if (feature)
3092 return S_OK;
3093 i++;
3096 return USP_E_SCRIPT_NOT_IN_FONT;