usp10: Add Kannada script.
[wine.git] / dlls / usp10 / shape.c
blobb535cd558fc21550161ee94c5d0586f7ff92b6ef
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);
56 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
58 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);
59 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 );
60 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 );
61 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 );
62 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 );
63 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 );
64 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 );
65 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 );
66 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 );
67 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 );
68 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 );
69 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 );
70 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 extern const unsigned short wine_shaping_table[];
73 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
75 enum joining_types {
76 jtU,
77 jtT,
78 jtR,
79 jtL,
80 jtD,
81 jtC
84 enum joined_forms {
85 Xn=0,
86 Xr,
87 Xl,
88 Xm,
89 /* Syriac Alaph */
90 Afj,
91 Afn,
92 Afx
95 #ifdef WORDS_BIGENDIAN
96 #define GET_BE_WORD(x) (x)
97 #else
98 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
99 #endif
101 /* These are all structures needed for the GSUB table */
102 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
103 #define GSUB_E_NOFEATURE -2
104 #define GSUB_E_NOGLYPH -1
106 typedef struct {
107 DWORD version;
108 WORD ScriptList;
109 WORD FeatureList;
110 WORD LookupList;
111 } GSUB_Header;
113 typedef struct {
114 CHAR ScriptTag[4];
115 WORD Script;
116 } GSUB_ScriptRecord;
118 typedef struct {
119 WORD ScriptCount;
120 GSUB_ScriptRecord ScriptRecord[1];
121 } GSUB_ScriptList;
123 typedef struct {
124 CHAR LangSysTag[4];
125 WORD LangSys;
126 } GSUB_LangSysRecord;
128 typedef struct {
129 WORD DefaultLangSys;
130 WORD LangSysCount;
131 GSUB_LangSysRecord LangSysRecord[1];
132 } GSUB_Script;
134 typedef struct {
135 WORD LookupOrder; /* Reserved */
136 WORD ReqFeatureIndex;
137 WORD FeatureCount;
138 WORD FeatureIndex[1];
139 } GSUB_LangSys;
141 typedef struct {
142 CHAR FeatureTag[4];
143 WORD Feature;
144 } GSUB_FeatureRecord;
146 typedef struct {
147 WORD FeatureCount;
148 GSUB_FeatureRecord FeatureRecord[1];
149 } GSUB_FeatureList;
151 typedef struct {
152 WORD FeatureParams; /* Reserved */
153 WORD LookupCount;
154 WORD LookupListIndex[1];
155 } GSUB_Feature;
157 typedef struct {
158 WORD LookupCount;
159 WORD Lookup[1];
160 } GSUB_LookupList;
162 typedef struct {
163 WORD LookupType;
164 WORD LookupFlag;
165 WORD SubTableCount;
166 WORD SubTable[1];
167 } GSUB_LookupTable;
169 typedef struct {
170 WORD CoverageFormat;
171 WORD GlyphCount;
172 WORD GlyphArray[1];
173 } GSUB_CoverageFormat1;
175 typedef struct {
176 WORD Start;
177 WORD End;
178 WORD StartCoverageIndex;
179 } GSUB_RangeRecord;
181 typedef struct {
182 WORD CoverageFormat;
183 WORD RangeCount;
184 GSUB_RangeRecord RangeRecord[1];
185 } GSUB_CoverageFormat2;
187 typedef struct {
188 WORD SubstFormat; /* = 1 */
189 WORD Coverage;
190 WORD DeltaGlyphID;
191 } GSUB_SingleSubstFormat1;
193 typedef struct {
194 WORD SubstFormat; /* = 2 */
195 WORD Coverage;
196 WORD GlyphCount;
197 WORD Substitute[1];
198 }GSUB_SingleSubstFormat2;
200 typedef struct {
201 WORD SubstFormat; /* = 1 */
202 WORD Coverage;
203 WORD LigSetCount;
204 WORD LigatureSet[1];
205 }GSUB_LigatureSubstFormat1;
207 typedef struct {
208 WORD LigatureCount;
209 WORD Ligature[1];
210 }GSUB_LigatureSet;
212 typedef struct{
213 WORD LigGlyph;
214 WORD CompCount;
215 WORD Component[1];
216 }GSUB_Ligature;
218 typedef struct{
219 WORD SequenceIndex;
220 WORD LookupListIndex;
222 }GSUB_SubstLookupRecord;
224 typedef struct{
225 WORD SubstFormat; /* = 1 */
226 WORD Coverage;
227 WORD ChainSubRuleSetCount;
228 WORD ChainSubRuleSet[1];
229 }GSUB_ChainContextSubstFormat1;
231 typedef struct {
232 WORD SubstFormat; /* = 3 */
233 WORD BacktrackGlyphCount;
234 WORD Coverage[1];
235 }GSUB_ChainContextSubstFormat3_1;
237 typedef struct{
238 WORD InputGlyphCount;
239 WORD Coverage[1];
240 }GSUB_ChainContextSubstFormat3_2;
242 typedef struct{
243 WORD LookaheadGlyphCount;
244 WORD Coverage[1];
245 }GSUB_ChainContextSubstFormat3_3;
247 typedef struct{
248 WORD SubstCount;
249 GSUB_SubstLookupRecord SubstLookupRecord[1];
250 }GSUB_ChainContextSubstFormat3_4;
252 typedef struct {
253 WORD SubstFormat; /* = 1 */
254 WORD Coverage;
255 WORD AlternateSetCount;
256 WORD AlternateSet[1];
257 } GSUB_AlternateSubstFormat1;
259 typedef struct{
260 WORD GlyphCount;
261 WORD Alternate[1];
262 } GSUB_AlternateSet;
264 /* These are all structures needed for the GDEF table */
265 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
267 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
269 typedef struct {
270 DWORD Version;
271 WORD GlyphClassDef;
272 WORD AttachList;
273 WORD LigCaretList;
274 WORD MarkAttachClassDef;
275 } GDEF_Header;
277 typedef struct {
278 WORD ClassFormat;
279 WORD StartGlyph;
280 WORD GlyphCount;
281 WORD ClassValueArray[1];
282 } GDEF_ClassDefFormat1;
284 typedef struct {
285 WORD Start;
286 WORD End;
287 WORD Class;
288 } GDEF_ClassRangeRecord;
290 typedef struct {
291 WORD ClassFormat;
292 WORD ClassRangeCount;
293 GDEF_ClassRangeRecord ClassRangeRecord[1];
294 } GDEF_ClassDefFormat2;
296 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
298 typedef struct tagVowelComponents
300 WCHAR base;
301 WCHAR parts[3];
302 } VowelComponents;
304 typedef struct tagConsonantComponents
306 WCHAR parts[3];
307 WCHAR output;
308 } ConsonantComponents;
310 /* the orders of joined_forms and contextual_features need to line up */
311 static const char* contextual_features[] =
313 "isol",
314 "fina",
315 "init",
316 "medi",
317 /* Syriac Alaph */
318 "med2",
319 "fin2",
320 "fin3"
323 static OPENTYPE_FEATURE_RECORD standard_features[] =
325 { MS_MAKE_TAG('l','i','g','a'), 1},
326 { MS_MAKE_TAG('c','l','i','g'), 1},
329 static OPENTYPE_FEATURE_RECORD arabic_features[] =
331 { MS_MAKE_TAG('r','l','i','g'), 1},
332 { MS_MAKE_TAG('c','a','l','t'), 1},
333 { MS_MAKE_TAG('l','i','g','a'), 1},
334 { MS_MAKE_TAG('d','l','i','g'), 1},
335 { MS_MAKE_TAG('c','s','w','h'), 1},
336 { MS_MAKE_TAG('m','s','e','t'), 1},
339 static const char* required_arabic_features[] =
341 "fina",
342 "init",
343 "medi",
344 "rlig",
345 NULL
348 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
350 { MS_MAKE_TAG('d','l','i','g'), 1},
353 static OPENTYPE_FEATURE_RECORD syriac_features[] =
355 { MS_MAKE_TAG('r','l','i','g'), 1},
356 { MS_MAKE_TAG('c','a','l','t'), 1},
357 { MS_MAKE_TAG('l','i','g','a'), 1},
358 { MS_MAKE_TAG('d','l','i','g'), 1},
361 static const char* required_syriac_features[] =
363 "fina",
364 "fin2",
365 "fin3",
366 "init",
367 "medi",
368 "med2",
369 "rlig",
370 NULL
373 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
375 /* Base forms */
376 { MS_MAKE_TAG('a','k','h','n'), 1},
377 { MS_MAKE_TAG('r','p','h','f'), 1},
378 { MS_MAKE_TAG('v','a','t','u'), 1},
379 { MS_MAKE_TAG('p','s','t','f'), 1},
380 /* Presentation forms */
381 { MS_MAKE_TAG('b','l','w','s'), 1},
382 { MS_MAKE_TAG('a','b','v','s'), 1},
383 { MS_MAKE_TAG('p','s','t','s'), 1},
386 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
388 { MS_MAKE_TAG('a','b','v','s'), 1},
389 { MS_MAKE_TAG('b','l','w','s'), 1},
392 static OPENTYPE_FEATURE_RECORD thai_features[] =
394 { MS_MAKE_TAG('c','c','m','p'), 1},
397 static const char* required_lao_features[] =
399 "ccmp",
400 NULL
403 static const char* required_devanagari_features[] =
405 "nukt",
406 "akhn",
407 "rphf",
408 "blwf",
409 "half",
410 "vatu",
411 "pres",
412 "abvs",
413 "blws",
414 "psts",
415 "haln",
416 NULL
419 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
421 /* Localized forms */
422 { MS_MAKE_TAG('l','o','c','l'), 1},
423 /* Base forms */
424 { MS_MAKE_TAG('n','u','k','t'), 1},
425 { MS_MAKE_TAG('a','k','h','n'), 1},
426 { MS_MAKE_TAG('r','p','h','f'), 1},
427 { MS_MAKE_TAG('r','k','r','f'), 1},
428 { MS_MAKE_TAG('b','l','w','f'), 1},
429 { MS_MAKE_TAG('h','a','l','f'), 1},
430 { MS_MAKE_TAG('v','a','t','u'), 1},
431 { MS_MAKE_TAG('c','j','c','t'), 1},
432 /* Presentation forms */
433 { MS_MAKE_TAG('p','r','e','s'), 1},
434 { MS_MAKE_TAG('a','b','v','s'), 1},
435 { MS_MAKE_TAG('b','l','w','s'), 1},
436 { MS_MAKE_TAG('p','s','t','s'), 1},
437 { MS_MAKE_TAG('h','a','l','n'), 1},
438 { MS_MAKE_TAG('c','a','l','t'), 1},
441 static const char* required_bengali_features[] =
443 "nukt",
444 "akhn",
445 "rphf",
446 "blwf",
447 "half",
448 "vatu",
449 "pstf",
450 "init",
451 "abvs",
452 "blws",
453 "psts",
454 "haln",
455 NULL
458 static OPENTYPE_FEATURE_RECORD bengali_features[] =
460 /* Localized forms */
461 { MS_MAKE_TAG('l','o','c','l'), 1},
462 /* Base forms */
463 { MS_MAKE_TAG('n','u','k','t'), 1},
464 { MS_MAKE_TAG('a','k','h','n'), 1},
465 { MS_MAKE_TAG('r','p','h','f'), 1},
466 { MS_MAKE_TAG('b','l','w','f'), 1},
467 { MS_MAKE_TAG('h','a','l','f'), 1},
468 { MS_MAKE_TAG('p','s','t','f'), 1},
469 { MS_MAKE_TAG('v','a','t','u'), 1},
470 { MS_MAKE_TAG('c','j','c','t'), 1},
471 /* Presentation forms */
472 { MS_MAKE_TAG('i','n','i','t'), 1},
473 { MS_MAKE_TAG('p','r','e','s'), 1},
474 { MS_MAKE_TAG('a','b','v','s'), 1},
475 { MS_MAKE_TAG('b','l','w','s'), 1},
476 { MS_MAKE_TAG('p','s','t','s'), 1},
477 { MS_MAKE_TAG('h','a','l','n'), 1},
478 { MS_MAKE_TAG('c','a','l','t'), 1},
481 static const char* required_gurmukhi_features[] =
483 "nukt",
484 "akhn",
485 "rphf",
486 "blwf",
487 "half",
488 "pstf",
489 "vatu",
490 "cjct",
491 "pres",
492 "abvs",
493 "blws",
494 "psts",
495 "haln",
496 "calt",
497 NULL
500 static OPENTYPE_FEATURE_RECORD gurmukhi_features[] =
502 /* Localized forms */
503 { MS_MAKE_TAG('l','o','c','l'), 1},
504 /* Base forms */
505 { MS_MAKE_TAG('n','u','k','t'), 1},
506 { MS_MAKE_TAG('a','k','h','n'), 1},
507 { MS_MAKE_TAG('r','p','h','f'), 1},
508 { MS_MAKE_TAG('b','l','w','f'), 1},
509 { MS_MAKE_TAG('h','a','l','f'), 1},
510 { MS_MAKE_TAG('p','s','t','f'), 1},
511 { MS_MAKE_TAG('v','a','t','u'), 1},
512 { MS_MAKE_TAG('c','j','c','t'), 1},
513 /* Presentation forms */
514 { MS_MAKE_TAG('p','r','e','s'), 1},
515 { MS_MAKE_TAG('a','b','v','s'), 1},
516 { MS_MAKE_TAG('b','l','w','s'), 1},
517 { MS_MAKE_TAG('p','s','t','s'), 1},
518 { MS_MAKE_TAG('h','a','l','n'), 1},
519 { MS_MAKE_TAG('c','a','l','t'), 1},
522 static const char* required_oriya_features[] =
524 "nukt",
525 "akhn",
526 "rphf",
527 "blwf",
528 "pstf",
529 "cjct",
530 "pres",
531 "abvs",
532 "blws",
533 "psts",
534 "haln",
535 "calt",
536 NULL
539 static OPENTYPE_FEATURE_RECORD oriya_features[] =
541 /* Localized forms */
542 { MS_MAKE_TAG('l','o','c','l'), 1},
543 /* Base forms */
544 { MS_MAKE_TAG('n','u','k','t'), 1},
545 { MS_MAKE_TAG('a','k','h','n'), 1},
546 { MS_MAKE_TAG('r','p','h','f'), 1},
547 { MS_MAKE_TAG('b','l','w','f'), 1},
548 { MS_MAKE_TAG('p','s','t','f'), 1},
549 { MS_MAKE_TAG('c','j','c','t'), 1},
550 /* Presentation forms */
551 { MS_MAKE_TAG('p','r','e','s'), 1},
552 { MS_MAKE_TAG('a','b','v','s'), 1},
553 { MS_MAKE_TAG('b','l','w','s'), 1},
554 { MS_MAKE_TAG('p','s','t','s'), 1},
555 { MS_MAKE_TAG('h','a','l','n'), 1},
556 { MS_MAKE_TAG('c','a','l','t'), 1},
559 static const char* required_tamil_features[] =
561 "nukt",
562 "akhn",
563 "rphf",
564 "pref",
565 "half",
566 "pres",
567 "abvs",
568 "blws",
569 "psts",
570 "haln",
571 "calt",
572 NULL
575 static OPENTYPE_FEATURE_RECORD tamil_features[] =
577 /* Localized forms */
578 { MS_MAKE_TAG('l','o','c','l'), 1},
579 /* Base forms */
580 { MS_MAKE_TAG('n','u','k','t'), 1},
581 { MS_MAKE_TAG('a','k','h','n'), 1},
582 { MS_MAKE_TAG('r','p','h','f'), 1},
583 { MS_MAKE_TAG('p','r','e','f'), 1},
584 { MS_MAKE_TAG('h','a','l','f'), 1},
585 /* Presentation forms */
586 { MS_MAKE_TAG('p','r','e','s'), 1},
587 { MS_MAKE_TAG('a','b','v','s'), 1},
588 { MS_MAKE_TAG('b','l','w','s'), 1},
589 { MS_MAKE_TAG('p','s','t','s'), 1},
590 { MS_MAKE_TAG('h','a','l','n'), 1},
591 { MS_MAKE_TAG('c','a','l','t'), 1},
594 static const char* required_telugu_features[] =
596 "nukt",
597 "akhn",
598 "rphf",
599 "pref",
600 "half",
601 "pstf",
602 "cjct",
603 "pres",
604 "abvs",
605 "blws",
606 "psts",
607 "haln",
608 "calt",
609 NULL
612 static OPENTYPE_FEATURE_RECORD telugu_features[] =
614 /* Localized forms */
615 { MS_MAKE_TAG('l','o','c','l'), 1},
616 /* Base forms */
617 { MS_MAKE_TAG('n','u','k','t'), 1},
618 { MS_MAKE_TAG('a','k','h','n'), 1},
619 { MS_MAKE_TAG('r','p','h','f'), 1},
620 { MS_MAKE_TAG('p','r','e','f'), 1},
621 { MS_MAKE_TAG('b','l','w','f'), 1},
622 { MS_MAKE_TAG('h','a','l','f'), 1},
623 { MS_MAKE_TAG('p','s','t','f'), 1},
624 { MS_MAKE_TAG('c','j','c','t'), 1},
625 /* Presentation forms */
626 { MS_MAKE_TAG('p','r','e','s'), 1},
627 { MS_MAKE_TAG('a','b','v','s'), 1},
628 { MS_MAKE_TAG('b','l','w','s'), 1},
629 { MS_MAKE_TAG('p','s','t','s'), 1},
630 { MS_MAKE_TAG('h','a','l','n'), 1},
631 { MS_MAKE_TAG('c','a','l','t'), 1},
634 typedef struct ScriptShapeDataTag {
635 TEXTRANGE_PROPERTIES defaultTextRange;
636 const char** requiredFeatures;
637 CHAR otTag[5];
638 CHAR newOtTag[5];
639 ContextualShapingProc contextProc;
640 ShapeCharGlyphPropProc charGlyphPropProc;
641 } ScriptShapeData;
643 /* in order of scripts */
644 static const ScriptShapeData ShapingData[] =
646 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
647 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
648 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
649 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
650 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
651 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
652 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
653 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
654 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
655 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
656 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
657 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
658 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
659 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
660 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
661 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
662 {{ sinhala_features, 7}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
663 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
664 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
665 {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
666 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
667 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
668 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
669 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
670 {{ devanagari_features, 15}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
671 {{ devanagari_features, 15}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
672 {{ bengali_features, 16}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
673 {{ bengali_features, 16}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
674 {{ gurmukhi_features, 15}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
675 {{ gurmukhi_features, 15}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
676 {{ devanagari_features, 15}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
677 {{ devanagari_features, 15}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
678 {{ devanagari_features, 15}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
679 {{ oriya_features, 13}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
680 {{ oriya_features, 13}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
681 {{ tamil_features, 12}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
682 {{ tamil_features, 12}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
683 {{ telugu_features, 15}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
684 {{ telugu_features, 15}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
685 {{ telugu_features, 15}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
686 {{ telugu_features, 15}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
689 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
691 const GSUB_CoverageFormat1* cf1;
693 cf1 = table;
695 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
697 int count = GET_BE_WORD(cf1->GlyphCount);
698 int i;
699 TRACE("Coverage Format 1, %i glyphs\n",count);
700 for (i = 0; i < count; i++)
701 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
702 return i;
703 return -1;
705 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
707 const GSUB_CoverageFormat2* cf2;
708 int i;
709 int count;
710 cf2 = (const GSUB_CoverageFormat2*)cf1;
712 count = GET_BE_WORD(cf2->RangeCount);
713 TRACE("Coverage Format 2, %i ranges\n",count);
714 for (i = 0; i < count; i++)
716 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
717 return -1;
718 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
719 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
721 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
722 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
725 return -1;
727 else
728 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
730 return -1;
733 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
735 const GSUB_ScriptList *script;
736 const GSUB_Script *deflt = NULL;
737 int i;
738 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
740 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
741 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
743 const GSUB_Script *scr;
744 int offset;
746 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
747 scr = (const GSUB_Script*)((const BYTE*)script + offset);
749 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
750 return scr;
751 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
752 deflt = scr;
754 return deflt;
757 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
759 int i;
760 int offset;
761 const GSUB_LangSys *Lang;
763 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
765 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
767 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
768 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
770 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
771 return Lang;
773 offset = GET_BE_WORD(script->DefaultLangSys);
774 if (offset)
776 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
777 return Lang;
779 return NULL;
782 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
784 int i;
785 const GSUB_FeatureList *feature;
786 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
788 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
789 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
791 int index = GET_BE_WORD(lang->FeatureIndex[i]);
792 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
794 const GSUB_Feature *feat;
795 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
796 return feat;
799 return NULL;
802 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
804 int j;
805 TRACE("Single Substitution Subtable\n");
807 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
809 int offset;
810 const GSUB_SingleSubstFormat1 *ssf1;
811 offset = GET_BE_WORD(look->SubTable[j]);
812 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
813 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
815 int offset = GET_BE_WORD(ssf1->Coverage);
816 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
817 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
819 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
820 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
821 TRACE(" 0x%x\n",glyphs[glyph_index]);
822 return glyph_index + 1;
825 else
827 const GSUB_SingleSubstFormat2 *ssf2;
828 INT index;
829 INT offset;
831 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
832 offset = GET_BE_WORD(ssf1->Coverage);
833 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
834 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
835 TRACE(" Coverage index %i\n",index);
836 if (index != -1)
838 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
839 return GSUB_E_NOGLYPH;
841 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
842 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
843 TRACE("0x%x\n",glyphs[glyph_index]);
844 return glyph_index + 1;
848 return GSUB_E_NOGLYPH;
851 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
853 int j;
854 TRACE("Alternate Substitution Subtable\n");
856 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
858 int offset;
859 const GSUB_AlternateSubstFormat1 *asf1;
860 INT index;
862 offset = GET_BE_WORD(look->SubTable[j]);
863 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
864 offset = GET_BE_WORD(asf1->Coverage);
866 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
867 if (index != -1)
869 const GSUB_AlternateSet *as;
870 offset = GET_BE_WORD(asf1->AlternateSet[index]);
871 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
872 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
873 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
874 return GSUB_E_NOGLYPH;
876 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
877 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
878 TRACE(" 0x%x\n",glyphs[glyph_index]);
879 return glyph_index + 1;
882 return GSUB_E_NOGLYPH;
885 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
887 int j;
889 TRACE("Ligature Substitution Subtable\n");
890 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
892 const GSUB_LigatureSubstFormat1 *lsf1;
893 int offset,index;
895 offset = GET_BE_WORD(look->SubTable[j]);
896 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
897 offset = GET_BE_WORD(lsf1->Coverage);
898 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
899 TRACE(" Coverage index %i\n",index);
900 if (index != -1)
902 const GSUB_LigatureSet *ls;
903 int k, count;
905 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
906 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
907 count = GET_BE_WORD(ls->LigatureCount);
908 TRACE(" LigatureSet has %i members\n",count);
909 for (k = 0; k < count; k++)
911 const GSUB_Ligature *lig;
912 int CompCount,l,CompIndex;
914 offset = GET_BE_WORD(ls->Ligature[k]);
915 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
916 CompCount = GET_BE_WORD(lig->CompCount) - 1;
917 CompIndex = glyph_index+write_dir;
918 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
920 int CompGlyph;
921 CompGlyph = GET_BE_WORD(lig->Component[l]);
922 if (CompGlyph != glyphs[CompIndex])
923 break;
924 CompIndex += write_dir;
926 if (l == CompCount)
928 int replaceIdx = glyph_index;
929 if (write_dir < 0)
930 replaceIdx = glyph_index - CompCount;
932 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
933 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
934 TRACE("0x%x\n",glyphs[replaceIdx]);
935 if (CompCount > 0)
937 int j;
938 for (j = replaceIdx + 1; j < *glyph_count; j++)
939 glyphs[j] =glyphs[j+CompCount];
940 *glyph_count = *glyph_count - CompCount;
942 return replaceIdx + 1;
947 return GSUB_E_NOGLYPH;
950 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
952 int j;
953 BOOL done = FALSE;
955 TRACE("Chaining Contextual Substitution Subtable\n");
956 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
958 const GSUB_ChainContextSubstFormat1 *ccsf1;
959 int offset;
960 int dirLookahead = write_dir;
961 int dirBacktrack = -1 * write_dir;
963 offset = GET_BE_WORD(look->SubTable[j]);
964 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
965 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
967 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
968 return -1;
970 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
972 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
973 return -1;
975 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
977 int k;
978 int indexGlyphs;
979 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
980 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
981 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
982 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
983 int newIndex = glyph_index;
985 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
987 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
989 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
991 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
992 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
993 break;
995 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
996 return -1;
997 TRACE("Matched Backtrack\n");
999 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
1001 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
1002 for (k = 0; k < indexGlyphs; k++)
1004 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
1005 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
1006 break;
1008 if (k != indexGlyphs)
1009 return -1;
1010 TRACE("Matched IndexGlyphs\n");
1012 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
1014 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
1016 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
1017 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
1018 break;
1020 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
1021 return -1;
1022 TRACE("Matched LookAhead\n");
1024 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
1026 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
1028 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
1029 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
1031 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1032 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
1033 if (newIndex == -1)
1035 ERR("Chain failed to generate a glyph\n");
1036 return -1;
1039 return newIndex + 1;
1042 return -1;
1045 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1047 int offset;
1048 const GSUB_LookupTable *look;
1050 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1051 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1052 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1053 switch(GET_BE_WORD(look->LookupType))
1055 case 1:
1056 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1057 case 3:
1058 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1059 case 4:
1060 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1061 case 6:
1062 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1063 default:
1064 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1066 return GSUB_E_NOGLYPH;
1069 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1071 int i;
1072 int out_index = GSUB_E_NOGLYPH;
1073 const GSUB_LookupList *lookup;
1075 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1077 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1078 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1080 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1081 if (out_index != GSUB_E_NOGLYPH)
1082 break;
1084 if (out_index == GSUB_E_NOGLYPH)
1085 TRACE("lookups found no glyphs\n");
1086 else
1088 int out2;
1089 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1090 if (out2!=GSUB_E_NOGLYPH)
1091 out_index = out2;
1093 return out_index;
1096 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1098 UINT charset;
1100 if (psc->userScript != 0)
1102 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1103 return ShapingData[psa->eScript].newOtTag;
1104 else
1105 return (char*)&psc->userScript;
1108 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1109 return ShapingData[psa->eScript].newOtTag;
1111 if (ShapingData[psa->eScript].otTag[0] != 0)
1112 return ShapingData[psa->eScript].otTag;
1115 * fall back to the font charset
1117 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1118 switch (charset)
1120 case ANSI_CHARSET: return "latn";
1121 case BALTIC_CHARSET: return "latn"; /* ?? */
1122 case CHINESEBIG5_CHARSET: return "hani";
1123 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1124 case GB2312_CHARSET: return "hani";
1125 case GREEK_CHARSET: return "grek";
1126 case HANGUL_CHARSET: return "hang";
1127 case RUSSIAN_CHARSET: return "cyrl";
1128 case SHIFTJIS_CHARSET: return "kana";
1129 case TURKISH_CHARSET: return "latn"; /* ?? */
1130 case VIETNAMESE_CHARSET: return "latn";
1131 case JOHAB_CHARSET: return "latn"; /* ?? */
1132 case ARABIC_CHARSET: return "arab";
1133 case HEBREW_CHARSET: return "hebr";
1134 case THAI_CHARSET: return "thai";
1135 default: return "latn";
1139 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1141 const GSUB_Feature *feature;
1142 int i;
1144 for (i = 0; i < psc->feature_count; i++)
1145 if (strncmp(psc->features[i].tag,feat,4)==0)
1146 return psc->features[i].feature;
1148 feature = NULL;
1150 if (psc->GSUB_Table)
1152 const GSUB_Script *script;
1153 const GSUB_LangSys *language;
1154 int attempt = 2;
1158 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1159 attempt--;
1160 if (script)
1162 if (psc->userLang != 0)
1163 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1164 else
1165 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1166 if (language)
1167 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1169 } while(attempt && !feature);
1171 /* try in the default (latin) table */
1172 if (!feature)
1174 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1175 if (script)
1177 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1178 if (language)
1179 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1184 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1186 psc->feature_count++;
1188 if (psc->features)
1189 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1190 else
1191 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1193 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1194 psc->features[psc->feature_count - 1].feature = feature;
1195 return feature;
1198 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)
1200 const GSUB_Feature *feature;
1202 feature = load_GSUB_feature(hdc, psa, psc, feat);
1203 if (!feature)
1204 return GSUB_E_NOFEATURE;
1206 TRACE("applying feature %s\n",feat);
1207 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1210 static VOID *load_gsub_table(HDC hdc)
1212 VOID* GSUB_Table = NULL;
1213 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1214 if (length != GDI_ERROR)
1216 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1217 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1218 TRACE("Loaded GSUB table of %i bytes\n",length);
1220 return GSUB_Table;
1223 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1225 int offset;
1226 WORD class = 0;
1227 const GDEF_ClassDefFormat1 *cf1;
1229 if (!header)
1230 return 0;
1232 offset = GET_BE_WORD(header->GlyphClassDef);
1233 if (!offset)
1234 return 0;
1236 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1237 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1239 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1241 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1242 if (index < GET_BE_WORD(cf1->GlyphCount))
1243 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1246 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1248 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1249 int i, top;
1250 top = GET_BE_WORD(cf2->ClassRangeCount);
1251 for (i = 0; i < top; i++)
1253 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1254 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1256 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1257 break;
1261 else
1262 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1264 return class;
1267 static VOID *load_gdef_table(HDC hdc)
1269 VOID* GDEF_Table = NULL;
1270 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1271 if (length != GDI_ERROR)
1273 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1274 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1275 TRACE("Loaded GDEF table of %i bytes\n",length);
1277 return GDEF_Table;
1280 static void GDEF_UpdateGlyphProps(HDC hdc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1282 VOID* header = load_gdef_table(hdc);
1283 int i;
1285 for (i = 0; i < cGlyphs; i++)
1287 WORD class;
1289 class = GDEF_get_glyph_class(header, pwGlyphs[i]);
1291 switch (class)
1293 case 0:
1294 case BaseGlyph:
1295 pGlyphProp[i].sva.fClusterStart = 1;
1296 pGlyphProp[i].sva.fDiacritic = 0;
1297 pGlyphProp[i].sva.fZeroWidth = 0;
1298 break;
1299 case LigatureGlyph:
1300 pGlyphProp[i].sva.fClusterStart = 1;
1301 pGlyphProp[i].sva.fDiacritic = 0;
1302 pGlyphProp[i].sva.fZeroWidth = 0;
1303 break;
1304 case MarkGlyph:
1305 pGlyphProp[i].sva.fClusterStart = 0;
1306 pGlyphProp[i].sva.fDiacritic = 1;
1307 pGlyphProp[i].sva.fZeroWidth = 1;
1308 break;
1309 case ComponentGlyph:
1310 pGlyphProp[i].sva.fClusterStart = 0;
1311 pGlyphProp[i].sva.fDiacritic = 0;
1312 pGlyphProp[i].sva.fZeroWidth = 0;
1313 break;
1314 default:
1315 ERR("Unknown glyph class %i\n",class);
1316 pGlyphProp[i].sva.fClusterStart = 1;
1317 pGlyphProp[i].sva.fDiacritic = 0;
1318 pGlyphProp[i].sva.fZeroWidth = 0;
1323 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1325 int i;
1327 for (i = 0; i < cGlyphs; i++)
1329 if (!pGlyphProp[i].sva.fClusterStart)
1331 int j;
1332 for (j = 0; j < cChars; j++)
1334 if (pwLogClust[j] == i)
1336 int k = j;
1337 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1338 k-=1;
1339 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1340 pwLogClust[j] = pwLogClust[k];
1347 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1349 if (changeCount == 0)
1350 return;
1351 else
1353 int i;
1354 int target_glyph = nextIndex - 1;
1355 int target_index = -1;
1356 int replacing_glyph = -1;
1357 int changed = 0;
1359 if (write_dir > 0)
1360 for (i = 0; i < chars; i++)
1362 if (pwLogClust[i] == target_glyph)
1364 target_index = i;
1365 break;
1368 else
1369 for (i = chars - 1; i >= 0; i--)
1371 if (pwLogClust[i] == target_glyph)
1373 target_index = i;
1374 break;
1377 if (target_index == -1)
1379 ERR("Unable to find target glyph\n");
1380 return;
1383 if (changeCount < 0)
1385 /* merge glyphs */
1386 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1388 if (pwLogClust[i] == target_glyph)
1389 continue;
1390 if(pwLogClust[i] == replacing_glyph)
1391 pwLogClust[i] = target_glyph;
1392 else
1394 changed--;
1395 if (changed >= changeCount)
1397 replacing_glyph = pwLogClust[i];
1398 pwLogClust[i] = target_glyph;
1400 else
1401 break;
1406 /* renumber trailing indexes*/
1407 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1409 if (pwLogClust[i] != target_glyph)
1410 pwLogClust[i] += changeCount;
1415 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 )
1417 int i;
1419 if (psc->GSUB_Table)
1421 const GSUB_Feature *feature;
1423 feature = load_GSUB_feature(hdc, psa, psc, feat);
1424 if (!feature)
1425 return GSUB_E_NOFEATURE;
1427 i = 0;
1428 TRACE("applying feature %s\n",debugstr_an(feat,4));
1429 while(i < *pcGlyphs)
1431 INT nextIndex;
1432 INT prevCount = *pcGlyphs;
1433 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1434 if (nextIndex > GSUB_E_NOGLYPH)
1436 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1437 i = nextIndex;
1439 else
1440 i++;
1442 return *pcGlyphs;
1444 return GSUB_E_NOFEATURE;
1447 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1449 if (i + delta < 0)
1450 return 0;
1451 if ( i+ delta >= cchLen)
1452 return 0;
1454 i += delta;
1456 return chars[i];
1459 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1461 if (i + delta < 0)
1463 if (psa->fLinkBefore)
1464 return jtR;
1465 else
1466 return jtU;
1468 if ( i+ delta >= cchLen)
1470 if (psa->fLinkAfter)
1471 return jtL;
1472 else
1473 return jtU;
1476 i += delta;
1478 if (context_type[i] == jtT)
1479 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1480 else
1481 return context_type[i];
1484 static inline BOOL right_join_causing(CHAR joining_type)
1486 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1489 static inline BOOL left_join_causing(CHAR joining_type)
1491 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1494 static inline BOOL word_break_causing(WCHAR chr)
1496 /* we are working within a string of characters already guareented to
1497 be within one script, Syriac, so we do not worry about any characers
1498 other than the space character outside of that range */
1499 return (chr == 0 || chr == 0x20 );
1503 * ContextualShape_Arabic
1505 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1507 CHAR *context_type;
1508 INT *context_shape;
1509 INT dirR, dirL;
1510 int i;
1512 if (*pcGlyphs != cChars)
1514 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1515 return;
1518 if (!psa->fLogicalOrder && psa->fRTL)
1520 dirR = 1;
1521 dirL = -1;
1523 else
1525 dirR = -1;
1526 dirL = 1;
1529 if (!psc->GSUB_Table)
1530 psc->GSUB_Table = load_gsub_table(hdc);
1532 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1533 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1535 for (i = 0; i < cChars; i++)
1536 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1538 for (i = 0; i < cChars; i++)
1540 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1541 context_shape[i] = Xr;
1542 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1543 context_shape[i] = Xl;
1544 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)))
1545 context_shape[i] = Xm;
1546 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1547 context_shape[i] = Xr;
1548 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1549 context_shape[i] = Xl;
1550 else
1551 context_shape[i] = Xn;
1554 /* Contextual Shaping */
1555 i = 0;
1556 while(i < *pcGlyphs)
1558 BOOL shaped = FALSE;
1560 if (psc->GSUB_Table)
1562 INT nextIndex;
1563 INT prevCount = *pcGlyphs;
1564 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1565 if (nextIndex > GSUB_E_NOGLYPH)
1567 i = nextIndex;
1568 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1570 shaped = (nextIndex > GSUB_E_NOGLYPH);
1573 if (!shaped)
1575 WORD newGlyph = pwOutGlyphs[i];
1576 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1578 /* fall back to presentation form B */
1579 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1580 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1581 pwOutGlyphs[i] = newGlyph;
1583 i++;
1587 HeapFree(GetProcessHeap(),0,context_shape);
1588 HeapFree(GetProcessHeap(),0,context_type);
1592 * ContextualShape_Syriac
1595 #define ALAPH 0x710
1596 #define DALATH 0x715
1597 #define RISH 0x72A
1599 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1601 CHAR *context_type;
1602 INT *context_shape;
1603 INT dirR, dirL;
1604 int i;
1606 if (*pcGlyphs != cChars)
1608 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1609 return;
1612 if (!psa->fLogicalOrder && psa->fRTL)
1614 dirR = 1;
1615 dirL = -1;
1617 else
1619 dirR = -1;
1620 dirL = 1;
1623 if (!psc->GSUB_Table)
1624 psc->GSUB_Table = load_gsub_table(hdc);
1626 if (!psc->GSUB_Table)
1627 return;
1629 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1630 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1632 for (i = 0; i < cChars; i++)
1633 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1635 for (i = 0; i < cChars; i++)
1637 if (pwcChars[i] == ALAPH)
1639 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1641 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1642 context_shape[i] = Afj;
1643 else if ( rchar != DALATH && rchar != RISH &&
1644 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1645 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1646 context_shape[i] = Afn;
1647 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1648 context_shape[i] = Afx;
1649 else
1650 context_shape[i] = Xn;
1652 else if (context_type[i] == jtR &&
1653 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1654 context_shape[i] = Xr;
1655 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1656 context_shape[i] = Xl;
1657 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)))
1658 context_shape[i] = Xm;
1659 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1660 context_shape[i] = Xr;
1661 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1662 context_shape[i] = Xl;
1663 else
1664 context_shape[i] = Xn;
1667 /* Contextual Shaping */
1668 i = 0;
1669 while(i < *pcGlyphs)
1671 INT nextIndex;
1672 INT prevCount = *pcGlyphs;
1673 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1674 if (nextIndex > GSUB_E_NOGLYPH)
1676 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1677 i = nextIndex;
1679 else
1680 i++;
1683 HeapFree(GetProcessHeap(),0,context_shape);
1684 HeapFree(GetProcessHeap(),0,context_type);
1688 * ContextualShape_Phags_pa
1691 #define phags_pa_CANDRABINDU 0xA873
1692 #define phags_pa_START 0xA840
1693 #define phags_pa_END 0xA87F
1695 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1697 INT *context_shape;
1698 INT dirR, dirL;
1699 int i;
1701 if (*pcGlyphs != cChars)
1703 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1704 return;
1707 if (!psa->fLogicalOrder && psa->fRTL)
1709 dirR = 1;
1710 dirL = -1;
1712 else
1714 dirR = -1;
1715 dirL = 1;
1718 if (!psc->GSUB_Table)
1719 psc->GSUB_Table = load_gsub_table(hdc);
1721 if (!psc->GSUB_Table)
1722 return;
1724 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1726 for (i = 0; i < cChars; i++)
1728 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1730 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1731 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1732 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1733 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1735 if (jrchar && jlchar)
1736 context_shape[i] = Xm;
1737 else if (jrchar)
1738 context_shape[i] = Xr;
1739 else if (jlchar)
1740 context_shape[i] = Xl;
1741 else
1742 context_shape[i] = Xn;
1744 else
1745 context_shape[i] = -1;
1748 /* Contextual Shaping */
1749 i = 0;
1750 while(i < *pcGlyphs)
1752 if (context_shape[i] >= 0)
1754 INT nextIndex;
1755 INT prevCount = *pcGlyphs;
1756 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1757 if (nextIndex > GSUB_E_NOGLYPH)
1759 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1760 i = nextIndex;
1762 else
1763 i++;
1765 else
1766 i++;
1769 HeapFree(GetProcessHeap(),0,context_shape);
1772 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1774 int i;
1776 /* Replace */
1777 pwOutChars[cWalk] = replacements[0];
1778 cWalk=cWalk+1;
1780 /* Insert */
1781 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1783 int j;
1784 for (j = *pcChars; j > cWalk; j--)
1785 pwOutChars[j] = pwOutChars[j-1];
1786 *pcChars= *pcChars+1;
1787 pwOutChars[cWalk] = replacements[i];
1788 cWalk = cWalk+1;
1792 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1794 int i;
1795 int cWalk;
1797 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1799 for (i = 0; vowels[i].base != 0x0; i++)
1801 if (pwOutChars[cWalk] == vowels[i].base)
1803 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1804 break;
1810 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1812 int i;
1813 int cWalk;
1815 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1817 for (i = 0; consonants[i].output!= 0x0; i++)
1819 int j;
1820 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1821 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1822 break;
1824 if (consonants[i].parts[j]==0x0) /* matched all */
1826 int k;
1827 j--;
1828 pwOutChars[cWalk] = consonants[i].output;
1829 for(k = cWalk+1; k < *pcChars - j; k++)
1830 pwOutChars[k] = pwOutChars[k+j];
1831 *pcChars = *pcChars - j;
1832 break;
1835 cWalk++;
1839 static void Reorder_Ra_follows_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1841 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1843 int j;
1844 WORD Ra = pwChar[start];
1845 WORD H = pwChar[start+1];
1847 TRACE("Doing reorder of Ra to %i\n",main);
1848 for (j = start; j < main-1; j++)
1849 pwChar[j] = pwChar[j+2];
1850 pwChar[main-1] = Ra;
1851 pwChar[main] = H;
1855 static void Reorder_Ra_follows_mantra_post(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1857 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1859 int j,loc;
1860 WORD Ra = pwChar[start];
1861 WORD H = pwChar[start+1];
1862 for (loc = main; loc > end; loc++)
1863 if (lexical(pwChar[loc]) == lex_Mantra_post)
1864 break;
1865 if (loc == end) loc = main;
1867 TRACE("Doing reorder of Ra to %i\n",loc);
1868 for (j = start; j < loc-1; j++)
1869 pwChar[j] = pwChar[j+2];
1870 pwChar[loc-1] = Ra;
1871 pwChar[loc] = H;
1875 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1877 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1879 int j;
1880 WORD Ra = pwChar[start];
1881 WORD H = pwChar[start+1];
1883 TRACE("Doing reorder of Ra to %i\n",end-1);
1884 for (j = start; j < end-1; j++)
1885 pwChar[j] = pwChar[j+2];
1886 pwChar[end-1] = Ra;
1887 pwChar[end] = H;
1891 static void Reorder_Mantra_precede_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1893 int i;
1895 /* reorder Mantras */
1896 if (end > main)
1898 for (i = 1; i <= end-main; i++)
1900 if (lexical(pwChar[main+i]) == lex_Mantra_pre)
1902 int j;
1903 WCHAR c = pwChar[main+i];
1904 TRACE("Doing reorder of %x %x\n",c,pwChar[main]);
1905 for (j = main+i; j > main; j--)
1906 pwChar[j] = pwChar[j-1];
1907 pwChar[main] = c;
1913 static void Reorder_Mantra_precede_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1915 int i;
1917 /* reorder Mantras */
1918 if (end > main)
1920 for (i = 1; i <= end-main; i++)
1922 if (lexical(pwChar[main+i]) == lex_Mantra_pre)
1924 int j;
1925 WCHAR c = pwChar[main+i];
1926 TRACE("Doing reorder of %x to %i\n",c,start);
1927 for (j = main+i; j > start; j--)
1928 pwChar[j] = pwChar[j-1];
1929 pwChar[start] = c;
1935 static void Reorder_Like_Sinhala(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1937 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1938 if (start == main && main == end) return;
1940 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1941 if (lexical(pwChar[main]) == lex_Vowel) return;
1943 Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1944 Reorder_Mantra_precede_base(pwChar, start, main, end, lexical);
1947 static void Reorder_Like_Devanagari(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1949 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1950 if (start == main && main == end) return;
1952 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1953 if (lexical(pwChar[main]) == lex_Vowel) return;
1955 Reorder_Ra_follows_mantra_post(pwChar, start, main, end, lexical);
1956 Reorder_Mantra_precede_syllable(pwChar, start, main, end, lexical);
1959 static void Reorder_Like_Bengali(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1961 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1962 if (start == main && main == end) return;
1964 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1965 if (lexical(pwChar[main]) == lex_Vowel) return;
1967 Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1968 Reorder_Mantra_precede_syllable(pwChar, start, main, end, lexical);
1971 static void Reorder_Like_Kannada(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1973 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1974 if (start == main && main == end) return;
1976 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1977 if (lexical(pwChar[main]) == lex_Vowel) return;
1979 Reorder_Ra_follows_syllable(pwChar, start, main, end, lexical);
1980 Reorder_Mantra_precede_syllable(pwChar, start, main, end, lexical);
1983 static int sinhala_lex(WCHAR c)
1985 switch (c)
1987 case 0x0DCA: return lex_Halant;
1988 case 0x0DCF:
1989 case 0x0DDF:
1990 case 0x0DD8: return lex_Mantra_post;
1991 case 0x0DD9:
1992 case 0x0DDB: return lex_Mantra_pre;
1993 case 0x0DDA:
1994 case 0x0DDC: return lex_Composed_Vowel;
1995 case 0x200D: return lex_ZWJ;
1996 case 0x200C: return lex_ZWNJ;
1997 case 0x00A0: return lex_NBSP;
1998 default:
1999 if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
2000 else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
2001 else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
2002 else if (c>=0x0DD0 && c <=0x0DD1) return lex_Mantra_post;
2003 else if (c>=0x0DD2 && c <=0x0DD3) return lex_Mantra_above;
2004 else if (c>=0x0DD4 && c <=0x0DD6) return lex_Mantra_below;
2005 else if (c>=0x0DDD && c <=0x0DDE) return lex_Composed_Vowel;
2006 else if (c>=0x0DF2 && c <=0x0DF3) return lex_Mantra_post;
2007 else return lex_Generic;
2011 static const VowelComponents Sinhala_vowels[] = {
2012 {0x0DDA, {0x0DD9,0x0DCA,0x0}},
2013 {0x0DDC, {0x0DD9,0x0DCF,0x0}},
2014 {0x0DDD, {0x0DD9,0x0DCF,0x0DCA}},
2015 {0x0DDE, {0x0DD9,0x0DDF,0x0}},
2016 {0x0000, {0x0000,0x0000,0x0}}};
2018 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2020 int cCount = cChars;
2021 WCHAR *input;
2023 if (*pcGlyphs != cChars)
2025 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2026 return;
2029 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2031 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2033 /* Step 1: Decompose multi part vowels */
2034 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels);
2036 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2038 /* Step 2: Reorder within Syllables */
2039 Indic_ReorderCharacters( input, cCount, sinhala_lex, Reorder_Like_Sinhala);
2040 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2042 /* Step 3: Get glyphs */
2043 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2044 *pcGlyphs = cCount;
2046 HeapFree(GetProcessHeap(),0,input);
2049 static int devanagari_lex(WCHAR c)
2051 switch (c)
2053 case 0x0951:
2054 case 0x0952:
2055 case 0x0903: return lex_Modifier;
2056 case 0x0930: return lex_Ra;
2057 case 0x093C: return lex_Nukta;
2058 case 0x0940:
2059 case 0x093E: return lex_Mantra_post;
2060 case 0x093F: return lex_Mantra_pre;
2061 case 0x094D: return lex_Halant;
2062 case 0x0972: return lex_Vowel;
2063 case 0x200C: return lex_ZWNJ;
2064 case 0x200D: return lex_ZWJ;
2065 default:
2066 if (c>=0x0901 && c<=0x0902) return lex_Mantra_above;
2067 else if (c>=0x0904 && c<=0x0914) return lex_Vowel;
2068 else if (c>=0x0915 && c<=0x0939) return lex_Consonant;
2069 else if (c>=0x0941 && c<=0x0944) return lex_Mantra_below;
2070 else if (c>=0x0945 && c<=0x0948) return lex_Mantra_above;
2071 else if (c>=0x0949 && c<=0x094C) return lex_Mantra_post;
2072 else if (c>=0x0953 && c<=0x0954) return lex_Modifier;
2073 else if (c>=0x0958 && c<=0x095F) return lex_Consonant;
2074 else if (c>=0x0960 && c<=0x0961) return lex_Vowel;
2075 else if (c>=0x0962 && c<=0x0963) return lex_Mantra_below;
2076 else if (c>=0x097B && c<=0x097C) return lex_Consonant;
2077 else if (c>=0x097E && c<=0x097F) return lex_Consonant;
2078 else return lex_Generic;
2082 static const ConsonantComponents Devanagari_consonants[] ={
2083 {{0x0928, 0x093C, 0x00000}, 0x0929},
2084 {{0x0930, 0x093C, 0x00000}, 0x0931},
2085 {{0x0933, 0x093C, 0x00000}, 0x0934},
2086 {{0x0915, 0x093C, 0x00000}, 0x0958},
2087 {{0x0916, 0x093C, 0x00000}, 0x0959},
2088 {{0x0917, 0x093C, 0x00000}, 0x095A},
2089 {{0x091C, 0x093C, 0x00000}, 0x095B},
2090 {{0x0921, 0x093C, 0x00000}, 0x095C},
2091 {{0x0922, 0x093C, 0x00000}, 0x095D},
2092 {{0x092B, 0x093C, 0x00000}, 0x095E},
2093 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2095 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2097 int cCount = cChars;
2098 WCHAR *input;
2100 if (*pcGlyphs != cChars)
2102 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2103 return;
2106 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2107 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2109 /* Step 1: Compose Consonant and Nukta */
2110 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
2111 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2113 /* Step 2: Reorder within Syllables */
2114 Indic_ReorderCharacters( input, cCount, devanagari_lex, Reorder_Like_Devanagari);
2115 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2116 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2117 *pcGlyphs = cCount;
2119 HeapFree(GetProcessHeap(),0,input);
2122 static int bengali_lex(WCHAR c)
2124 switch (c)
2126 case 0x0981: return lex_Modifier;
2127 case 0x09AC:
2128 case 0x09AF:
2129 case 0x09CE: return lex_Consonant;
2130 case 0x09B0: return lex_Ra;
2131 case 0x09BC: return lex_Nukta;
2132 case 0x09BF: return lex_Mantra_pre;
2133 case 0x09D7:
2134 case 0x09BE:
2135 case 0x09C0: return lex_Mantra_post;
2136 case 0x09CD: return lex_Halant;
2137 case 0x200C: return lex_ZWNJ;
2138 case 0x200D: return lex_ZWJ;
2139 default:
2140 if (c>=0x0982 && c<=0x0983) return lex_Mantra_post;
2141 else if (c>=0x0985 && c<=0x0994) return lex_Vowel;
2142 else if (c>=0x0995 && c<=0x09B9) return lex_Consonant;
2143 else if (c>=0x09C1 && c<=0x09C4) return lex_Mantra_below;
2144 else if (c>=0x09C7 && c<=0x09C8) return lex_Mantra_pre;
2145 else if (c>=0x09DC && c<=0x09DF) return lex_Consonant;
2146 else if (c>=0x09E0 && c<=0x09E1) return lex_Vowel;
2147 else if (c>=0x09E2 && c<=0x09E3) return lex_Mantra_below;
2148 else if (c>=0x09F0 && c<=0x09F1) return lex_Consonant;
2149 else return lex_Generic;
2153 static const VowelComponents Bengali_vowels[] = {
2154 {0x09CB, {0x09C7,0x09BE,0x0000}},
2155 {0x09CC, {0x09C7,0x09D7,0x0000}},
2156 {0x0000, {0x0000,0x0000,0x0000}}};
2158 static const ConsonantComponents Bengali_consonants[] = {
2159 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2160 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2161 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2162 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2163 {{0x0000,0x0000,0x0000}, 0x0000}};
2165 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2167 int cCount = cChars;
2168 WCHAR *input;
2170 if (*pcGlyphs != cChars)
2172 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2173 return;
2176 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2177 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2179 /* Step 1: Decompose Vowels and Compose Consonents */
2180 DecomposeVowels(hdc, input, &cCount, Bengali_vowels);
2181 ComposeConsonants(hdc, input, &cCount, Bengali_consonants);
2182 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2184 /* Step 2: Reorder within Syllables */
2185 Indic_ReorderCharacters( input, cCount, bengali_lex, Reorder_Like_Bengali);
2186 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2187 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2188 *pcGlyphs = cCount;
2190 HeapFree(GetProcessHeap(),0,input);
2193 static int gurmukhi_lex(WCHAR c)
2195 switch (c)
2197 case 0x0A2f: return lex_Consonant;
2198 case 0x0A30:
2199 case 0x0A35:
2200 case 0x0A39: return lex_Ra;
2201 case 0x0A3C: return lex_Nukta;
2202 case 0x0A3F: return lex_Mantra_pre;
2203 case 0x0A03:
2204 case 0x0A3E:
2205 case 0x0A40: return lex_Mantra_post;
2206 case 0x0A4D: return lex_Halant;
2207 case 0x0A70:
2208 case 0x0A71: return lex_Modifier;
2209 case 0x200C: return lex_ZWNJ;
2210 case 0x200D: return lex_ZWJ;
2211 default:
2212 if (c>=0x0A01 && c<=0x0A02) return lex_Modifier;
2213 else if (c>=0x0A05 && c<=0x0A14) return lex_Vowel;
2214 else if (c>=0x0A15 && c<=0x0A38) return lex_Consonant;
2215 else if (c>=0x0A41 && c<=0x0A42) return lex_Mantra_below;
2216 else if (c>=0x0A47 && c<=0x0A4C) return lex_Mantra_above;
2217 else if (c>=0x0A59 && c<=0x0A5E) return lex_Consonant;
2218 else return lex_Generic;
2222 static const ConsonantComponents Gurmukhi_consonants[] = {
2223 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2224 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2225 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2226 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2227 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2228 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2229 {{0x0000,0x0000,0x0000}, 0x0000}};
2231 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2233 int cCount = cChars;
2234 WCHAR *input;
2236 if (*pcGlyphs != cChars)
2238 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2239 return;
2242 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2243 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2245 /* Step 1: Compose Consonents */
2246 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants);
2247 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2249 /* Step 2: Reorder within Syllables */
2250 Indic_ReorderCharacters( input, cCount, gurmukhi_lex, Reorder_Like_Bengali);
2251 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2252 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2253 *pcGlyphs = cCount;
2255 HeapFree(GetProcessHeap(),0,input);
2258 static int gujarati_lex(WCHAR c)
2260 switch (c)
2262 case 0x0A83: return lex_Modifier;
2263 case 0x0AB0: return lex_Ra;
2264 case 0x0ABC: return lex_Nukta;
2265 case 0x0ABF: return lex_Mantra_pre;
2266 case 0x0ABE:
2267 case 0x0AC0: return lex_Mantra_post;
2268 case 0x0ACD: return lex_Halant;
2269 case 0x200C: return lex_ZWNJ;
2270 case 0x200D: return lex_ZWJ;
2271 default:
2272 if (c>=0x0A81 && c<=0x0A82) return lex_Modifier;
2273 else if (c>=0x0A85 && c<=0x0A94) return lex_Vowel;
2274 else if (c>=0x0A95 && c<=0x0AB9) return lex_Consonant;
2275 else if (c>=0x0AC1 && c<=0x0AC4) return lex_Mantra_below;
2276 else if (c>=0x0AC5 && c<=0x0AC8) return lex_Mantra_above;
2277 else if (c>=0x0AC9 && c<=0x0ACC) return lex_Mantra_post;
2278 else if (c>=0x0AE0 && c<=0x0AE1) return lex_Vowel;
2279 else if (c>=0x0AE2 && c<=0x0AE3) return lex_Mantra_below;
2280 else return lex_Generic;
2284 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2286 int cCount = cChars;
2287 WCHAR *input;
2289 if (*pcGlyphs != cChars)
2291 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2292 return;
2295 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2296 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2298 /* Step 1: Reorder within Syllables */
2299 Indic_ReorderCharacters( input, cCount, gujarati_lex, Reorder_Like_Devanagari);
2300 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2301 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2302 *pcGlyphs = cCount;
2304 HeapFree(GetProcessHeap(),0,input);
2307 static int oriya_lex(WCHAR c)
2309 switch (c)
2311 case 0x0B24:
2312 case 0x0B28:
2313 case 0x0B2F:
2314 case 0x0B5F:
2315 case 0x0B71:
2316 case 0x0B33: return lex_Consonant;
2317 case 0x0B30: return lex_Ra;
2318 case 0x0B3C: return lex_Nukta;
2319 case 0x0B3F:
2320 case 0x0B56: return lex_Mantra_above;
2321 case 0x0B3E:
2322 case 0x0B40: return lex_Mantra_post;
2323 case 0x0B47:
2324 case 0x0B57: return lex_Mantra_pre;
2325 case 0x0B4D: return lex_Halant;
2326 case 0x200C: return lex_ZWNJ;
2327 case 0x200D: return lex_ZWJ;
2328 default:
2329 if (c>=0x0B01 && c<=0x0B03) return lex_Modifier;
2330 else if (c>=0x0B05 && c<=0x0B14) return lex_Vowel;
2331 else if (c>=0x0B15 && c<=0x0B39) return lex_Consonant;
2332 else if (c>=0x0B2C && c<=0x0B2E) return lex_Consonant;
2333 else if (c>=0x0B32 && c<=0x0B33) return lex_Consonant;
2334 else if (c>=0x0B41 && c<=0x0B44) return lex_Mantra_below;
2335 else if (c>=0x0B48 && c<=0x0B4C) return lex_Composed_Vowel;
2336 else if (c>=0x0B5C && c<=0x0B5D) return lex_Consonant;
2337 else if (c>=0x0B60 && c<=0x0B61) return lex_Vowel;
2338 else if (c>=0x0B62 && c<=0x0B63) return lex_Mantra_below;
2339 else return lex_Generic;
2343 static const VowelComponents Oriya_vowels[] = {
2344 {0x0B48, {0x0B47,0x0B56,0x0000}},
2345 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2346 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2347 {0x0000, {0x0000,0x0000,0x0000}}};
2349 static const ConsonantComponents Oriya_consonants[] = {
2350 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2351 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2352 {{0x0000,0x0000,0x0000}, 0x0000}};
2354 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2356 int cCount = cChars;
2357 WCHAR *input;
2359 if (*pcGlyphs != cChars)
2361 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2362 return;
2365 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2366 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2368 /* Step 1: Decompose Vowels and Compose Consonents */
2369 DecomposeVowels(hdc, input, &cCount, Oriya_vowels);
2370 ComposeConsonants(hdc, input, &cCount, Oriya_consonants);
2371 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2373 /* Step 2: Reorder within Syllables */
2374 Indic_ReorderCharacters( input, cCount, oriya_lex, Reorder_Like_Bengali);
2375 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2376 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2377 *pcGlyphs = cCount;
2379 HeapFree(GetProcessHeap(),0,input);
2382 static int tamil_lex(WCHAR c)
2384 switch (c)
2386 case 0x0BC0: return lex_Mantra_above;
2387 case 0x0BCD: return lex_Halant;
2388 case 0x0BD7: return lex_Mantra_post;
2389 case 0x200C: return lex_ZWNJ;
2390 case 0x200D: return lex_ZWJ;
2391 default:
2392 if (c>=0x0B95 && c<=0x0BB9) return lex_Consonant;
2393 else if (c>=0x0BBE && c<=0x0BBF) return lex_Mantra_post;
2394 else if (c>=0x0BC1 && c<=0x0BC2) return lex_Mantra_below;
2395 else if (c>=0x0BC6 && c<=0x0BC8) return lex_Mantra_pre;
2396 else return lex_Generic;
2400 static const VowelComponents Tamil_vowels[] = {
2401 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2402 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2403 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2404 {0x0000, {0x0000,0x0000,0x0000}}};
2406 static const ConsonantComponents Tamil_consonants[] = {
2407 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2408 {{0x0000,0x0000,0x0000}, 0x0000}};
2410 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2412 int cCount = cChars;
2413 WCHAR *input;
2415 if (*pcGlyphs != cChars)
2417 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2418 return;
2421 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2422 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2424 /* Step 1: Decompose Vowels and Compose Consonents */
2425 DecomposeVowels(hdc, input, &cCount, Tamil_vowels);
2426 ComposeConsonants(hdc, input, &cCount, Tamil_consonants);
2427 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2429 /* Step 2: Reorder within Syllables */
2430 Indic_ReorderCharacters( input, cCount, tamil_lex, Reorder_Like_Sinhala);
2431 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2432 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2433 *pcGlyphs = cCount;
2435 HeapFree(GetProcessHeap(),0,input);
2438 static int telugu_lex(WCHAR c)
2440 switch (c)
2442 case 0x0C4D: return lex_Halant;
2443 case 0x0C55: return lex_Mantra_above;
2444 case 0x0C56: return lex_Mantra_below;
2445 case 0x200C: return lex_ZWNJ;
2446 case 0x200D: return lex_ZWJ;
2447 default:
2448 if (c>=0x0C01 && c<=0x0C03) return lex_Mantra_post;
2449 else if (c>=0x0C05 && c<=0x0C14) return lex_Vowel;
2450 else if (c>=0x0C15 && c<=0x0C39) return lex_Consonant;
2451 else if (c>=0x0C3E && c<=0x0C40) return lex_Mantra_above;
2452 else if (c>=0x0C41 && c<=0x0C44) return lex_Mantra_post;
2453 else if (c>=0x0C46 && c<=0x0C47) return lex_Mantra_above;
2454 else if (c>=0x0C4A && c<=0x0C4C) return lex_Mantra_above;
2455 else if (c>=0x0C58 && c<=0x0C59) return lex_Consonant;
2456 else if (c>=0x0C60 && c<=0x0C61) return lex_Vowel;
2457 else if (c>=0x0C62 && c<=0x0C63) return lex_Mantra_below;
2458 else return lex_Generic;
2462 static const VowelComponents Telugu_vowels[] = {
2463 {0x0C48, {0x0C46,0x0C56,0x0000}},
2464 {0x0000, {0x0000,0x0000,0x0000}}};
2466 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2468 int cCount = cChars;
2469 WCHAR *input;
2471 if (*pcGlyphs != cChars)
2473 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2474 return;
2477 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2478 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2480 /* Step 1: Decompose Vowels */
2481 DecomposeVowels(hdc, input, &cCount, Telugu_vowels);
2482 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2484 /* Step 2: Reorder within Syllables */
2485 Indic_ReorderCharacters( input, cCount, telugu_lex, Reorder_Like_Bengali);
2486 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2487 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2488 *pcGlyphs = cCount;
2490 HeapFree(GetProcessHeap(),0,input);
2493 static int kannada_lex(WCHAR c)
2495 switch (c)
2497 case 0x0CB0: return lex_Ra;
2498 case 0x0CBC: return lex_Nukta;
2499 case 0x0CBE: return lex_Mantra_post;
2500 case 0x0CBF: return lex_Mantra_above;
2501 case 0x0CC6: return lex_Mantra_above;
2502 case 0x0CCC: return lex_Mantra_above;
2503 case 0x0CCD: return lex_Halant;
2504 case 0x0CCE: return lex_Consonant;
2505 case 0x200C: return lex_ZWNJ;
2506 case 0x200D: return lex_ZWJ;
2507 default:
2508 if (c>=0x0C82 && c<=0x0C83) return lex_Modifier;
2509 else if (c>=0x0C85 && c<=0x0C94) return lex_Vowel;
2510 else if (c>=0x0C95 && c<=0x0CB9) return lex_Consonant;
2511 else if (c>=0x0CC1 && c<=0x0CC4) return lex_Mantra_post;
2512 else if (c>=0x0CD5 && c<=0x0CD6) return lex_Modifier;
2513 else if (c>=0x0CE0 && c<=0x0CE1) return lex_Vowel;
2514 else if (c>=0x0CE2 && c<=0x0CE3) return lex_Mantra_below;
2515 else return lex_Generic;
2519 static const VowelComponents Kannada_vowels[] = {
2520 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2521 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2522 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2523 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2524 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2525 {0x0000, {0x0000,0x0000,0x0000}}};
2527 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2529 int cCount = cChars;
2530 WCHAR *input;
2532 if (*pcGlyphs != cChars)
2534 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2535 return;
2538 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2539 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2541 /* Step 1: Decompose Vowels */
2542 DecomposeVowels(hdc, input, &cCount, Kannada_vowels);
2543 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2545 /* Step 2: Reorder within Syllables */
2546 Indic_ReorderCharacters( input, cCount, kannada_lex, Reorder_Like_Kannada);
2547 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2548 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2549 *pcGlyphs = cCount;
2551 HeapFree(GetProcessHeap(),0,input);
2554 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)
2556 int i,k;
2558 for (i = 0; i < cGlyphs; i++)
2560 int char_index[20];
2561 int char_count = 0;
2563 for (k = 0; k < cChars; k++)
2565 if (pwLogClust[k] == i)
2567 char_index[char_count] = k;
2568 char_count++;
2572 if (char_count == 0)
2574 FIXME("No chars in this glyph? Must be an error\n");
2575 continue;
2578 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2580 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2581 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2583 else
2584 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2587 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2588 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2591 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 )
2593 int i,k;
2594 int initGlyph, finaGlyph;
2595 INT dirR, dirL;
2596 BYTE *spaces;
2598 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2599 memset(spaces,0,cGlyphs);
2601 if (!psa->fLogicalOrder && psa->fRTL)
2603 initGlyph = cGlyphs-1;
2604 finaGlyph = 0;
2605 dirR = 1;
2606 dirL = -1;
2608 else
2610 initGlyph = 0;
2611 finaGlyph = cGlyphs-1;
2612 dirR = -1;
2613 dirL = 1;
2616 for (i = 0; i < cGlyphs; i++)
2618 for (k = 0; k < cChars; k++)
2619 if (pwLogClust[k] == i)
2621 if (pwcChars[k] == 0x0020)
2622 spaces[i] = 1;
2626 for (i = 0; i < cGlyphs; i++)
2628 int char_index[20];
2629 int char_count = 0;
2630 BOOL isInit, isFinal;
2632 for (k = 0; k < cChars; k++)
2634 if (pwLogClust[k] == i)
2636 char_index[char_count] = k;
2637 char_count++;
2641 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2642 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2644 if (char_count == 0)
2646 FIXME("No chars in this glyph? Must be an error\n");
2647 continue;
2650 if (char_count == 1)
2652 if (pwcChars[char_index[0]] == 0x0020) /* space */
2654 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2655 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2657 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2658 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2659 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2661 if (!isInit && !isFinal)
2662 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2663 else if (isInit)
2664 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2665 else
2666 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2668 else if (!isInit)
2670 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2671 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2672 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2673 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2674 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2675 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2676 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2677 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2678 else
2679 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2681 else if (!isInit && !isFinal)
2682 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2683 else
2684 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2686 else if (char_count == 2)
2688 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2689 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2690 else if (!isInit)
2691 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2692 else
2693 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2695 else if (!isInit && !isFinal)
2696 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2697 else
2698 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2701 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2702 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2703 HeapFree(GetProcessHeap(),0,spaces);
2706 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 )
2708 int i,k;
2709 int finaGlyph;
2710 INT dirL;
2711 BYTE *spaces;
2713 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2714 memset(spaces,0,cGlyphs);
2716 if (!psa->fLogicalOrder && psa->fRTL)
2718 finaGlyph = 0;
2719 dirL = -1;
2721 else
2723 finaGlyph = cGlyphs-1;
2724 dirL = 1;
2727 for (i = 0; i < cGlyphs; i++)
2729 for (k = 0; k < cChars; k++)
2730 if (pwLogClust[k] == i)
2732 if (pwcChars[k] == 0x0020)
2733 spaces[i] = 1;
2737 for (i = 0; i < cGlyphs; i++)
2739 int char_index[20];
2740 int char_count = 0;
2742 for (k = 0; k < cChars; k++)
2744 if (pwLogClust[k] == i)
2746 char_index[char_count] = k;
2747 char_count++;
2751 if (char_count == 0)
2753 FIXME("No chars in this glyph? Must be an error\n");
2754 continue;
2757 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2759 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2760 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2762 else if (i == finaGlyph)
2763 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2764 else
2765 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2768 HeapFree(GetProcessHeap(),0,spaces);
2769 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2770 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2772 /* Do not allow justification between marks and their base */
2773 for (i = 0; i < cGlyphs; i++)
2775 if (!pGlyphProp[i].sva.fClusterStart)
2776 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2780 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)
2782 int i,k;
2784 for (i = 0; i < cGlyphs; i++)
2786 int char_index[20];
2787 int char_count = 0;
2789 for (k = 0; k < cChars; k++)
2791 if (pwLogClust[k] == i)
2793 char_index[char_count] = k;
2794 char_count++;
2798 if (char_count == 0)
2800 FIXME("No chars in this glyph? Must be an error\n");
2801 continue;
2804 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2806 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2807 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2809 else
2810 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2812 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2813 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2816 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)
2818 int i,k;
2820 for (i = 0; i < cGlyphs; i++)
2822 int char_index[20];
2823 int char_count = 0;
2825 for (k = 0; k < cChars; k++)
2827 if (pwLogClust[k] == i)
2829 char_index[char_count] = k;
2830 char_count++;
2834 if (char_count == 0)
2836 FIXME("No chars in this glyph? Must be an error\n");
2837 continue;
2840 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2842 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2843 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2845 else
2846 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2848 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2849 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2851 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2852 for (i = 0; i < cGlyphs; i++)
2854 if (!pGlyphProp[i].sva.fClusterStart)
2856 pGlyphProp[i].sva.fDiacritic = 0;
2857 pGlyphProp[i].sva.fZeroWidth = 0;
2862 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)
2864 int i,k;
2866 for (i = 0; i < cGlyphs; i++)
2868 int char_index[20];
2869 int char_count = 0;
2871 for (k = 0; k < cChars; k++)
2873 if (pwLogClust[k] == i)
2875 char_index[char_count] = k;
2876 char_count++;
2880 if (char_count == 0)
2882 FIXME("No chars in this glyph? Must be an error\n");
2883 continue;
2886 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2888 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2889 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2891 else
2892 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2894 pGlyphProp[i].sva.fClusterStart = 0;
2895 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2896 switch (lexical(pwcChars[char_index[k]]))
2898 case lex_Mantra_pre:
2899 case lex_Mantra_post:
2900 case lex_Mantra_above:
2901 case lex_Mantra_below:
2902 case lex_Modifier:
2903 break;
2904 default:
2905 pGlyphProp[i].sva.fClusterStart = 1;
2906 break;
2909 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2912 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 )
2914 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
2917 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 )
2919 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
2922 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 )
2924 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
2927 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 )
2929 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
2932 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 )
2934 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
2937 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 )
2939 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
2942 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 )
2944 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
2947 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 )
2949 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
2952 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)
2954 if (ShapingData[psa->eScript].charGlyphPropProc)
2955 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2956 else
2957 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2960 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2962 if (ShapingData[psa->eScript].contextProc)
2963 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2966 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)
2968 int i;
2969 INT dirL;
2971 if (!rpRangeProperties)
2972 return;
2974 if (!psc->GSUB_Table)
2975 psc->GSUB_Table = load_gsub_table(hdc);
2977 if (!psc->GSUB_Table)
2978 return;
2980 if (!psa->fLogicalOrder && psa->fRTL)
2981 dirL = -1;
2982 else
2983 dirL = 1;
2985 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
2987 if (rpRangeProperties->potfRecords[i].lParameter > 0)
2988 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
2992 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
2994 const TEXTRANGE_PROPERTIES *rpRangeProperties;
2995 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
2997 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3000 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3002 const GSUB_Feature *feature;
3003 int i;
3005 if (!ShapingData[psa->eScript].requiredFeatures)
3006 return S_OK;
3008 if (!psc->GSUB_Table)
3009 psc->GSUB_Table = load_gsub_table(hdc);
3011 /* we need to have at least one of the required features */
3012 i = 0;
3013 while (ShapingData[psa->eScript].requiredFeatures[i])
3015 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3016 if (feature)
3017 return S_OK;
3018 i++;
3021 return USP_E_SCRIPT_NOT_IN_FONT;