usp10: Code for the cmap format 12 table for unicode code points beyond the BMP.
[wine.git] / dlls / usp10 / shape.c
blobe889ba80a652b062b8f063670fec9cc204bc58af
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>
22 #include <stdlib.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #define FIRST_ARABIC_CHAR 0x0600
39 #define LAST_ARABIC_CHAR 0x06ff
41 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
42 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
62 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);
63 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 );
64 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 );
65 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 );
66 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 );
67 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
77 static void ShapeCharGlyphProp_Khmer( 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 );
79 extern const unsigned short indic_syllabic_table[];
80 extern const unsigned short wine_shaping_table[];
81 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
83 enum joining_types {
84 jtU,
85 jtT,
86 jtR,
87 jtL,
88 jtD,
89 jtC
92 enum joined_forms {
93 Xn=0,
94 Xr,
95 Xl,
96 Xm,
97 /* Syriac Alaph */
98 Afj,
99 Afn,
103 #ifdef WORDS_BIGENDIAN
104 #define GET_BE_WORD(x) (x)
105 #define GET_BE_DWORD(x) (x)
106 #else
107 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
108 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
109 #endif
111 /* These are all structures needed for the GSUB table */
112 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
113 #define GSUB_E_NOFEATURE -2
114 #define GSUB_E_NOGLYPH -1
116 typedef struct {
117 DWORD version;
118 WORD ScriptList;
119 WORD FeatureList;
120 WORD LookupList;
121 } GSUB_Header;
123 typedef struct {
124 CHAR ScriptTag[4];
125 WORD Script;
126 } GSUB_ScriptRecord;
128 typedef struct {
129 WORD ScriptCount;
130 GSUB_ScriptRecord ScriptRecord[1];
131 } GSUB_ScriptList;
133 typedef struct {
134 CHAR LangSysTag[4];
135 WORD LangSys;
136 } GSUB_LangSysRecord;
138 typedef struct {
139 WORD DefaultLangSys;
140 WORD LangSysCount;
141 GSUB_LangSysRecord LangSysRecord[1];
142 } GSUB_Script;
144 typedef struct {
145 WORD LookupOrder; /* Reserved */
146 WORD ReqFeatureIndex;
147 WORD FeatureCount;
148 WORD FeatureIndex[1];
149 } GSUB_LangSys;
151 typedef struct {
152 CHAR FeatureTag[4];
153 WORD Feature;
154 } GSUB_FeatureRecord;
156 typedef struct {
157 WORD FeatureCount;
158 GSUB_FeatureRecord FeatureRecord[1];
159 } GSUB_FeatureList;
161 typedef struct {
162 WORD FeatureParams; /* Reserved */
163 WORD LookupCount;
164 WORD LookupListIndex[1];
165 } GSUB_Feature;
167 typedef struct {
168 WORD LookupCount;
169 WORD Lookup[1];
170 } GSUB_LookupList;
172 typedef struct {
173 WORD LookupType;
174 WORD LookupFlag;
175 WORD SubTableCount;
176 WORD SubTable[1];
177 } GSUB_LookupTable;
179 typedef struct {
180 WORD CoverageFormat;
181 WORD GlyphCount;
182 WORD GlyphArray[1];
183 } GSUB_CoverageFormat1;
185 typedef struct {
186 WORD Start;
187 WORD End;
188 WORD StartCoverageIndex;
189 } GSUB_RangeRecord;
191 typedef struct {
192 WORD CoverageFormat;
193 WORD RangeCount;
194 GSUB_RangeRecord RangeRecord[1];
195 } GSUB_CoverageFormat2;
197 typedef struct {
198 WORD SubstFormat; /* = 1 */
199 WORD Coverage;
200 WORD DeltaGlyphID;
201 } GSUB_SingleSubstFormat1;
203 typedef struct {
204 WORD SubstFormat; /* = 2 */
205 WORD Coverage;
206 WORD GlyphCount;
207 WORD Substitute[1];
208 }GSUB_SingleSubstFormat2;
210 typedef struct {
211 WORD SubstFormat; /* = 1 */
212 WORD Coverage;
213 WORD SequenceCount;
214 WORD Sequence[1];
215 }GSUB_MultipleSubstFormat1;
217 typedef struct {
218 WORD GlyphCount;
219 WORD Substitute[1];
220 }GSUB_Sequence;
222 typedef struct {
223 WORD SubstFormat; /* = 1 */
224 WORD Coverage;
225 WORD LigSetCount;
226 WORD LigatureSet[1];
227 }GSUB_LigatureSubstFormat1;
229 typedef struct {
230 WORD LigatureCount;
231 WORD Ligature[1];
232 }GSUB_LigatureSet;
234 typedef struct{
235 WORD LigGlyph;
236 WORD CompCount;
237 WORD Component[1];
238 }GSUB_Ligature;
240 typedef struct{
241 WORD SequenceIndex;
242 WORD LookupListIndex;
244 }GSUB_SubstLookupRecord;
246 typedef struct{
247 WORD SubstFormat; /* = 1 */
248 WORD Coverage;
249 WORD ChainSubRuleSetCount;
250 WORD ChainSubRuleSet[1];
251 }GSUB_ChainContextSubstFormat1;
253 typedef struct {
254 WORD SubstFormat; /* = 3 */
255 WORD BacktrackGlyphCount;
256 WORD Coverage[1];
257 }GSUB_ChainContextSubstFormat3_1;
259 typedef struct{
260 WORD InputGlyphCount;
261 WORD Coverage[1];
262 }GSUB_ChainContextSubstFormat3_2;
264 typedef struct{
265 WORD LookaheadGlyphCount;
266 WORD Coverage[1];
267 }GSUB_ChainContextSubstFormat3_3;
269 typedef struct{
270 WORD SubstCount;
271 GSUB_SubstLookupRecord SubstLookupRecord[1];
272 }GSUB_ChainContextSubstFormat3_4;
274 typedef struct {
275 WORD SubstFormat; /* = 1 */
276 WORD Coverage;
277 WORD AlternateSetCount;
278 WORD AlternateSet[1];
279 } GSUB_AlternateSubstFormat1;
281 typedef struct{
282 WORD GlyphCount;
283 WORD Alternate[1];
284 } GSUB_AlternateSet;
286 /* These are all structures needed for the GDEF table */
287 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
289 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
291 typedef struct {
292 DWORD Version;
293 WORD GlyphClassDef;
294 WORD AttachList;
295 WORD LigCaretList;
296 WORD MarkAttachClassDef;
297 } GDEF_Header;
299 typedef struct {
300 WORD ClassFormat;
301 WORD StartGlyph;
302 WORD GlyphCount;
303 WORD ClassValueArray[1];
304 } GDEF_ClassDefFormat1;
306 typedef struct {
307 WORD Start;
308 WORD End;
309 WORD Class;
310 } GDEF_ClassRangeRecord;
312 typedef struct {
313 WORD ClassFormat;
314 WORD ClassRangeCount;
315 GDEF_ClassRangeRecord ClassRangeRecord[1];
316 } GDEF_ClassDefFormat2;
319 /* These are all structures needed for the cmap format 12 table */
320 #define CMAP_TAG MS_MAKE_TAG('c', 'm', 'a', 'p')
322 typedef struct {
323 WORD platformID;
324 WORD encodingID;
325 DWORD offset;
326 } CMAP_EncodingRecord;
328 typedef struct {
329 WORD version;
330 WORD numTables;
331 CMAP_EncodingRecord tables[1];
332 } CMAP_Header;
334 typedef struct {
335 DWORD startCharCode;
336 DWORD endCharCode;
337 DWORD startGlyphID;
338 } CMAP_SegmentedCoverage_group;
340 typedef struct {
341 WORD format;
342 WORD reserved;
343 DWORD length;
344 DWORD language;
345 DWORD nGroups;
346 CMAP_SegmentedCoverage_group groups[1];
347 } CMAP_SegmentedCoverage;
349 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
351 typedef struct tagVowelComponents
353 WCHAR base;
354 WCHAR parts[3];
355 } VowelComponents;
357 typedef struct tagConsonantComponents
359 WCHAR parts[3];
360 WCHAR output;
361 } ConsonantComponents;
363 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
365 /* the orders of joined_forms and contextual_features need to line up */
366 static const char* contextual_features[] =
368 "isol",
369 "fina",
370 "init",
371 "medi",
372 /* Syriac Alaph */
373 "med2",
374 "fin2",
375 "fin3"
378 static OPENTYPE_FEATURE_RECORD standard_features[] =
380 { MS_MAKE_TAG('c','c','m','p'), 1},
381 { MS_MAKE_TAG('l','o','c','l'), 1},
384 static OPENTYPE_FEATURE_RECORD latin_features[] =
386 { MS_MAKE_TAG('l','i','g','a'), 1},
387 { MS_MAKE_TAG('c','l','i','g'), 1},
390 static OPENTYPE_FEATURE_RECORD arabic_features[] =
392 { MS_MAKE_TAG('r','l','i','g'), 1},
393 { MS_MAKE_TAG('c','a','l','t'), 1},
394 { MS_MAKE_TAG('l','i','g','a'), 1},
395 { MS_MAKE_TAG('d','l','i','g'), 1},
396 { MS_MAKE_TAG('c','s','w','h'), 1},
397 { MS_MAKE_TAG('m','s','e','t'), 1},
400 static const char* required_arabic_features[] =
402 "fina",
403 "init",
404 "medi",
405 "rlig",
406 NULL
409 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
411 { MS_MAKE_TAG('d','l','i','g'), 0},
414 static OPENTYPE_FEATURE_RECORD syriac_features[] =
416 { MS_MAKE_TAG('r','l','i','g'), 1},
417 { MS_MAKE_TAG('c','a','l','t'), 1},
418 { MS_MAKE_TAG('l','i','g','a'), 1},
419 { MS_MAKE_TAG('d','l','i','g'), 1},
422 static const char* required_syriac_features[] =
424 "fina",
425 "fin2",
426 "fin3",
427 "init",
428 "medi",
429 "med2",
430 "rlig",
431 NULL
434 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
436 /* Presentation forms */
437 { MS_MAKE_TAG('b','l','w','s'), 1},
438 { MS_MAKE_TAG('a','b','v','s'), 1},
439 { MS_MAKE_TAG('p','s','t','s'), 1},
442 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
444 { MS_MAKE_TAG('a','b','v','s'), 1},
445 { MS_MAKE_TAG('b','l','w','s'), 1},
448 static OPENTYPE_FEATURE_RECORD phags_features[] =
450 { MS_MAKE_TAG('a','b','v','s'), 1},
451 { MS_MAKE_TAG('b','l','w','s'), 1},
452 { MS_MAKE_TAG('c','a','l','t'), 1},
455 static OPENTYPE_FEATURE_RECORD thai_features[] =
457 { MS_MAKE_TAG('c','c','m','p'), 1},
460 static const char* required_lao_features[] =
462 "ccmp",
463 NULL
466 static const char* required_devanagari_features[] =
468 "nukt",
469 "akhn",
470 "rphf",
471 "blwf",
472 "half",
473 "vatu",
474 "pres",
475 "abvs",
476 "blws",
477 "psts",
478 "haln",
479 NULL
482 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
484 { MS_MAKE_TAG('p','r','e','s'), 1},
485 { MS_MAKE_TAG('a','b','v','s'), 1},
486 { MS_MAKE_TAG('b','l','w','s'), 1},
487 { MS_MAKE_TAG('p','s','t','s'), 1},
488 { MS_MAKE_TAG('h','a','l','n'), 1},
489 { MS_MAKE_TAG('c','a','l','t'), 1},
492 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
494 { MS_MAKE_TAG('l','i','g','a'), 1},
495 { MS_MAKE_TAG('c','l','i','g'), 1},
498 static const char* required_bengali_features[] =
500 "nukt",
501 "akhn",
502 "rphf",
503 "blwf",
504 "half",
505 "vatu",
506 "pstf",
507 "init",
508 "abvs",
509 "blws",
510 "psts",
511 "haln",
512 NULL
515 static const char* required_gurmukhi_features[] =
517 "nukt",
518 "akhn",
519 "rphf",
520 "blwf",
521 "half",
522 "pstf",
523 "vatu",
524 "cjct",
525 "pres",
526 "abvs",
527 "blws",
528 "psts",
529 "haln",
530 "calt",
531 NULL
534 static const char* required_oriya_features[] =
536 "nukt",
537 "akhn",
538 "rphf",
539 "blwf",
540 "pstf",
541 "cjct",
542 "pres",
543 "abvs",
544 "blws",
545 "psts",
546 "haln",
547 "calt",
548 NULL
551 static const char* required_tamil_features[] =
553 "nukt",
554 "akhn",
555 "rphf",
556 "pref",
557 "half",
558 "pres",
559 "abvs",
560 "blws",
561 "psts",
562 "haln",
563 "calt",
564 NULL
567 static const char* required_telugu_features[] =
569 "nukt",
570 "akhn",
571 "rphf",
572 "pref",
573 "half",
574 "pstf",
575 "cjct",
576 "pres",
577 "abvs",
578 "blws",
579 "psts",
580 "haln",
581 "calt",
582 NULL
585 static OPENTYPE_FEATURE_RECORD khmer_features[] =
587 { MS_MAKE_TAG('p','r','e','s'), 1},
588 { MS_MAKE_TAG('b','l','w','s'), 1},
589 { MS_MAKE_TAG('a','b','v','s'), 1},
590 { MS_MAKE_TAG('p','s','t','s'), 1},
591 { MS_MAKE_TAG('c','l','i','g'), 1},
594 static const char* required_khmer_features[] =
596 "pref",
597 "blwf",
598 "abvf",
599 "pstf",
600 "pres",
601 "blws",
602 "abvs",
603 "psts",
604 "clig",
605 NULL
608 static OPENTYPE_FEATURE_RECORD no_features[] =
609 { };
611 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
613 { MS_MAKE_TAG('c','c','m','p'), 1},
614 { MS_MAKE_TAG('l','o','c','l'), 1},
615 { MS_MAKE_TAG('c','a','l','t'), 1},
616 { MS_MAKE_TAG('l','i','g','a'), 1},
619 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
621 { MS_MAKE_TAG('c','c','m','p'), 1},
622 { MS_MAKE_TAG('l','o','c','l'), 1},
623 { MS_MAKE_TAG('c','a','l','t'), 1},
624 { MS_MAKE_TAG('r','l','i','g'), 1},
627 typedef struct ScriptShapeDataTag {
628 TEXTRANGE_PROPERTIES defaultTextRange;
629 const char** requiredFeatures;
630 CHAR otTag[5];
631 CHAR newOtTag[5];
632 ContextualShapingProc contextProc;
633 ShapeCharGlyphPropProc charGlyphPropProc;
634 } ScriptShapeData;
636 /* in order of scripts */
637 static const ScriptShapeData ShapingData[] =
639 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
640 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
641 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
642 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
643 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
644 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
645 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
646 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
647 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
648 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
649 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
650 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
651 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
652 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
653 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
654 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
655 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
656 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
657 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
658 {{ phags_features, 3}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
659 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
660 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
661 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
662 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
663 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
664 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
665 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
666 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
667 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
668 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
669 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
670 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
671 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
672 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
673 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
674 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
675 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
676 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
677 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
678 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
679 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
680 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
681 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
682 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
683 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
684 {{ latin_features, 2}, NULL, "latn" , "", NULL, NULL},
685 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
686 {{ myanmar_features, 2}, NULL, "mymr", "", NULL, NULL},
687 {{ myanmar_features, 2}, NULL, "mymr", "", NULL, NULL},
688 {{ standard_features, 2}, NULL, "tale", "", NULL, NULL},
689 {{ standard_features, 2}, NULL, "talu", "", NULL, NULL},
690 {{ standard_features, 2}, NULL, "talu", "", NULL, NULL},
691 {{ khmer_features, 5}, required_khmer_features, "khmr", "", ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
692 {{ khmer_features, 5}, required_khmer_features, "khmr", "", ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
693 {{ no_features, 0}, NULL, "hani", "", NULL, NULL},
694 {{ no_features, 0}, NULL, "hani", "", NULL, NULL},
695 {{ no_features, 0}, NULL, "bopo", "", NULL, NULL},
696 {{ no_features, 0}, NULL, "kana", "", NULL, NULL},
697 {{ no_features, 0}, NULL, "hang", "", NULL, NULL},
698 {{ no_features, 0}, NULL, "yi ", "", NULL, NULL},
699 {{ ethiopic_features, 4}, NULL, "ethi", "", NULL, NULL},
700 {{ ethiopic_features, 4}, NULL, "ethi", "", NULL, NULL},
701 {{ mongolian_features, 4}, NULL, "mong", "", ContextualShape_Mongolian, NULL},
702 {{ mongolian_features, 4}, NULL, "mong", "", ContextualShape_Mongolian, NULL},
703 {{ no_features, 0}, NULL, "tfng", "", NULL, NULL},
704 {{ no_features, 0}, NULL, "nko ", "", NULL, NULL},
705 {{ no_features, 0}, NULL, "vai ", "", NULL, NULL},
706 {{ no_features, 0}, NULL, "vai ", "", NULL, NULL},
707 {{ no_features, 0}, NULL, "cher", "", NULL, NULL},
708 {{ no_features, 0}, NULL, "cans", "", NULL, NULL},
709 {{ no_features, 0}, NULL, "ogam", "", NULL, NULL},
710 {{ no_features, 0}, NULL, "runr", "", NULL, NULL},
711 {{ no_features, 0}, NULL, "brai", "", NULL, NULL},
712 {{ no_features, 0}, NULL, "", "", NULL, NULL},
713 {{ no_features, 0}, NULL, "", "", NULL, NULL},
716 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
718 const GSUB_CoverageFormat1* cf1;
720 cf1 = table;
722 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
724 int count = GET_BE_WORD(cf1->GlyphCount);
725 int i;
726 TRACE("Coverage Format 1, %i glyphs\n",count);
727 for (i = 0; i < count; i++)
728 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
729 return i;
730 return -1;
732 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
734 const GSUB_CoverageFormat2* cf2;
735 int i;
736 int count;
737 cf2 = (const GSUB_CoverageFormat2*)cf1;
739 count = GET_BE_WORD(cf2->RangeCount);
740 TRACE("Coverage Format 2, %i ranges\n",count);
741 for (i = 0; i < count; i++)
743 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
744 return -1;
745 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
746 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
748 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
749 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
752 return -1;
754 else
755 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
757 return -1;
760 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
762 const GSUB_ScriptList *script;
763 const GSUB_Script *deflt = NULL;
764 int i;
765 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
767 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
768 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
770 const GSUB_Script *scr;
771 int offset;
773 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
774 scr = (const GSUB_Script*)((const BYTE*)script + offset);
776 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
777 return scr;
778 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
779 deflt = scr;
781 return deflt;
784 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
786 int i;
787 int offset;
788 const GSUB_LangSys *Lang;
790 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
792 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
794 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
795 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
797 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
798 return Lang;
800 offset = GET_BE_WORD(script->DefaultLangSys);
801 if (offset)
803 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
804 return Lang;
806 return NULL;
809 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
811 int i;
812 const GSUB_FeatureList *feature;
813 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
815 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
816 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
818 int index = GET_BE_WORD(lang->FeatureIndex[i]);
819 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
821 const GSUB_Feature *feat;
822 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
823 return feat;
826 return NULL;
829 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
831 int j;
832 TRACE("Single Substitution Subtable\n");
834 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
836 int offset;
837 const GSUB_SingleSubstFormat1 *ssf1;
838 offset = GET_BE_WORD(look->SubTable[j]);
839 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
840 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
842 int offset = GET_BE_WORD(ssf1->Coverage);
843 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
844 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
846 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
847 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
848 TRACE(" 0x%x\n",glyphs[glyph_index]);
849 return glyph_index + write_dir;
852 else
854 const GSUB_SingleSubstFormat2 *ssf2;
855 INT index;
856 INT offset;
858 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
859 offset = GET_BE_WORD(ssf1->Coverage);
860 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
861 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
862 TRACE(" Coverage index %i\n",index);
863 if (index != -1)
865 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
866 return GSUB_E_NOGLYPH;
868 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
869 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
870 TRACE("0x%x\n",glyphs[glyph_index]);
871 return glyph_index + write_dir;
875 return GSUB_E_NOGLYPH;
878 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
880 int j;
881 TRACE("Multiple Substitution Subtable\n");
883 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
885 int offset, index;
886 const GSUB_MultipleSubstFormat1 *msf1;
887 offset = GET_BE_WORD(look->SubTable[j]);
888 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
890 offset = GET_BE_WORD(msf1->Coverage);
891 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
892 if (index != -1)
894 const GSUB_Sequence *seq;
895 int sub_count;
896 int j;
897 offset = GET_BE_WORD(msf1->Sequence[index]);
898 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
899 sub_count = GET_BE_WORD(seq->GlyphCount);
900 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
902 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
903 glyphs[j] =glyphs[j-(sub_count-1)];
905 for (j = 0; j < sub_count; j++)
906 if (write_dir < 0)
907 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
908 else
909 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
911 *glyph_count = *glyph_count + (sub_count - 1);
913 if (TRACE_ON(uniscribe))
915 for (j = 0; j < sub_count; j++)
916 TRACE(" 0x%x",glyphs[glyph_index+j]);
917 TRACE("\n");
920 return glyph_index + (sub_count * write_dir);
923 return GSUB_E_NOGLYPH;
926 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
928 int j;
929 TRACE("Alternate Substitution Subtable\n");
931 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
933 int offset;
934 const GSUB_AlternateSubstFormat1 *asf1;
935 INT index;
937 offset = GET_BE_WORD(look->SubTable[j]);
938 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
939 offset = GET_BE_WORD(asf1->Coverage);
941 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
942 if (index != -1)
944 const GSUB_AlternateSet *as;
945 offset = GET_BE_WORD(asf1->AlternateSet[index]);
946 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
947 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
948 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
949 return GSUB_E_NOGLYPH;
951 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
952 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
953 TRACE(" 0x%x\n",glyphs[glyph_index]);
954 return glyph_index + write_dir;
957 return GSUB_E_NOGLYPH;
960 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
962 int j;
964 TRACE("Ligature Substitution Subtable\n");
965 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
967 const GSUB_LigatureSubstFormat1 *lsf1;
968 int offset,index;
970 offset = GET_BE_WORD(look->SubTable[j]);
971 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
972 offset = GET_BE_WORD(lsf1->Coverage);
973 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
974 TRACE(" Coverage index %i\n",index);
975 if (index != -1)
977 const GSUB_LigatureSet *ls;
978 int k, count;
980 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
981 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
982 count = GET_BE_WORD(ls->LigatureCount);
983 TRACE(" LigatureSet has %i members\n",count);
984 for (k = 0; k < count; k++)
986 const GSUB_Ligature *lig;
987 int CompCount,l,CompIndex;
989 offset = GET_BE_WORD(ls->Ligature[k]);
990 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
991 CompCount = GET_BE_WORD(lig->CompCount) - 1;
992 CompIndex = glyph_index+write_dir;
993 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
995 int CompGlyph;
996 CompGlyph = GET_BE_WORD(lig->Component[l]);
997 if (CompGlyph != glyphs[CompIndex])
998 break;
999 CompIndex += write_dir;
1001 if (l == CompCount)
1003 int replaceIdx = glyph_index;
1004 if (write_dir < 0)
1005 replaceIdx = glyph_index - CompCount;
1007 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
1008 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
1009 TRACE("0x%x\n",glyphs[replaceIdx]);
1010 if (CompCount > 0)
1012 int j;
1013 for (j = replaceIdx + 1; j < *glyph_count; j++)
1014 glyphs[j] =glyphs[j+CompCount];
1015 *glyph_count = *glyph_count - CompCount;
1017 return replaceIdx + write_dir;
1022 return GSUB_E_NOGLYPH;
1025 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1027 int j;
1028 BOOL done = FALSE;
1030 TRACE("Chaining Contextual Substitution Subtable\n");
1031 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
1033 const GSUB_ChainContextSubstFormat1 *ccsf1;
1034 int offset;
1035 int dirLookahead = write_dir;
1036 int dirBacktrack = -1 * write_dir;
1038 offset = GET_BE_WORD(look->SubTable[j]);
1039 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
1040 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
1042 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
1043 continue;
1045 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
1047 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
1048 continue;
1050 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
1052 int k;
1053 int indexGlyphs;
1054 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
1055 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
1056 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
1057 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
1058 int newIndex = glyph_index;
1060 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
1062 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
1064 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
1066 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
1067 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
1068 break;
1070 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
1071 continue;
1072 TRACE("Matched Backtrack\n");
1074 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
1076 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
1077 for (k = 0; k < indexGlyphs; k++)
1079 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
1080 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
1081 break;
1083 if (k != indexGlyphs)
1084 continue;
1085 TRACE("Matched IndexGlyphs\n");
1087 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
1089 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
1091 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
1092 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
1093 break;
1095 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
1096 continue;
1097 TRACE("Matched LookAhead\n");
1099 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
1101 if (GET_BE_WORD(ccsf3_4->SubstCount))
1103 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
1105 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
1106 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
1108 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1109 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
1110 if (newIndex == -1)
1112 ERR("Chain failed to generate a glyph\n");
1113 continue;
1116 return newIndex;
1118 else return GSUB_E_NOGLYPH;
1121 return -1;
1124 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1126 int offset;
1127 const GSUB_LookupTable *look;
1129 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1130 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1131 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1132 switch(GET_BE_WORD(look->LookupType))
1134 case 1:
1135 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1136 case 2:
1137 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1138 case 3:
1139 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1140 case 4:
1141 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1142 case 6:
1143 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1144 default:
1145 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1147 return GSUB_E_NOGLYPH;
1150 static INT GSUB_apply_feature_all_lookups(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1152 int i;
1153 int out_index = GSUB_E_NOGLYPH;
1154 const GSUB_LookupList *lookup;
1156 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1158 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1159 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1161 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1162 if (out_index != GSUB_E_NOGLYPH)
1163 break;
1165 if (out_index == GSUB_E_NOGLYPH)
1166 TRACE("lookups found no glyphs\n");
1167 else
1169 int out2;
1170 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1171 if (out2!=GSUB_E_NOGLYPH)
1172 out_index = out2;
1174 return out_index;
1177 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1179 UINT charset;
1181 if (psc->userScript != 0)
1183 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1184 return ShapingData[psa->eScript].newOtTag;
1185 else
1186 return (char*)&psc->userScript;
1189 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1190 return ShapingData[psa->eScript].newOtTag;
1192 if (ShapingData[psa->eScript].otTag[0] != 0)
1193 return ShapingData[psa->eScript].otTag;
1196 * fall back to the font charset
1198 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1199 switch (charset)
1201 case ANSI_CHARSET: return "latn";
1202 case BALTIC_CHARSET: return "latn"; /* ?? */
1203 case CHINESEBIG5_CHARSET: return "hani";
1204 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1205 case GB2312_CHARSET: return "hani";
1206 case GREEK_CHARSET: return "grek";
1207 case HANGUL_CHARSET: return "hang";
1208 case RUSSIAN_CHARSET: return "cyrl";
1209 case SHIFTJIS_CHARSET: return "kana";
1210 case TURKISH_CHARSET: return "latn"; /* ?? */
1211 case VIETNAMESE_CHARSET: return "latn";
1212 case JOHAB_CHARSET: return "latn"; /* ?? */
1213 case ARABIC_CHARSET: return "arab";
1214 case HEBREW_CHARSET: return "hebr";
1215 case THAI_CHARSET: return "thai";
1216 default: return "latn";
1220 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1222 const GSUB_Feature *feature;
1223 const char* script;
1224 int i;
1226 script = get_opentype_script(hdc,psa,psc,FALSE);
1228 for (i = 0; i < psc->feature_count; i++)
1230 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1231 return psc->features[i].feature;
1234 feature = NULL;
1236 if (psc->GSUB_Table)
1238 const GSUB_Script *script;
1239 const GSUB_LangSys *language;
1240 int attempt = 2;
1244 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1245 attempt--;
1246 if (script)
1248 if (psc->userLang != 0)
1249 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1250 else
1251 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1252 if (language)
1253 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1255 } while(attempt && !feature);
1257 /* try in the default (latin) table */
1258 if (!feature)
1260 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1261 if (script)
1263 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1264 if (language)
1265 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1270 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1272 psc->feature_count++;
1274 if (psc->features)
1275 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1276 else
1277 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1279 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1280 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1281 psc->features[psc->feature_count - 1].feature = feature;
1282 return feature;
1285 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)
1287 const GSUB_Feature *feature;
1289 feature = load_GSUB_feature(hdc, psa, psc, feat);
1290 if (!feature)
1291 return GSUB_E_NOFEATURE;
1293 TRACE("applying feature %s\n",feat);
1294 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1297 static VOID *load_gsub_table(HDC hdc)
1299 VOID* GSUB_Table = NULL;
1300 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1301 if (length != GDI_ERROR)
1303 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1304 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1305 TRACE("Loaded GSUB table of %i bytes\n",length);
1307 return GSUB_Table;
1310 INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature)
1312 WORD *glyphs;
1313 INT glyph_count = count;
1314 INT rc;
1316 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1317 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1318 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1319 if (rc > GSUB_E_NOGLYPH)
1320 rc = count - glyph_count;
1321 else
1322 rc = 0;
1324 HeapFree(GetProcessHeap(),0,glyphs);
1325 return rc;
1328 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1330 int offset;
1331 WORD class = 0;
1332 const GDEF_ClassDefFormat1 *cf1;
1334 if (!header)
1335 return 0;
1337 offset = GET_BE_WORD(header->GlyphClassDef);
1338 if (!offset)
1339 return 0;
1341 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1342 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1344 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1346 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1347 if (index < GET_BE_WORD(cf1->GlyphCount))
1348 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1351 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1353 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1354 int i, top;
1355 top = GET_BE_WORD(cf2->ClassRangeCount);
1356 for (i = 0; i < top; i++)
1358 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1359 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1361 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1362 break;
1366 else
1367 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1369 return class;
1372 static VOID *load_gdef_table(HDC hdc)
1374 VOID* GDEF_Table = NULL;
1375 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1376 if (length != GDI_ERROR)
1378 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1379 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1380 TRACE("Loaded GDEF table of %i bytes\n",length);
1382 return GDEF_Table;
1385 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
1387 int i;
1389 if (!psc->GDEF_Table)
1390 psc->GDEF_Table = load_gdef_table(hdc);
1392 for (i = 0; i < cGlyphs; i++)
1394 WORD class;
1395 int char_count = 0;
1396 int k;
1398 for (k = 0; k < cChars; k++)
1399 if (pwLogClust[k] == i)
1400 char_count++;
1402 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1404 switch (class)
1406 case 0:
1407 case BaseGlyph:
1408 pGlyphProp[i].sva.fClusterStart = 1;
1409 pGlyphProp[i].sva.fDiacritic = 0;
1410 pGlyphProp[i].sva.fZeroWidth = 0;
1411 break;
1412 case LigatureGlyph:
1413 pGlyphProp[i].sva.fClusterStart = 1;
1414 pGlyphProp[i].sva.fDiacritic = 0;
1415 pGlyphProp[i].sva.fZeroWidth = 0;
1416 break;
1417 case MarkGlyph:
1418 pGlyphProp[i].sva.fClusterStart = 0;
1419 pGlyphProp[i].sva.fDiacritic = 1;
1420 pGlyphProp[i].sva.fZeroWidth = 1;
1421 break;
1422 case ComponentGlyph:
1423 pGlyphProp[i].sva.fClusterStart = 0;
1424 pGlyphProp[i].sva.fDiacritic = 0;
1425 pGlyphProp[i].sva.fZeroWidth = 0;
1426 break;
1427 default:
1428 ERR("Unknown glyph class %i\n",class);
1429 pGlyphProp[i].sva.fClusterStart = 1;
1430 pGlyphProp[i].sva.fDiacritic = 0;
1431 pGlyphProp[i].sva.fZeroWidth = 0;
1434 if (char_count == 0)
1435 pGlyphProp[i].sva.fClusterStart = 0;
1439 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1441 int i;
1443 for (i = 0; i < cGlyphs; i++)
1445 if (!pGlyphProp[i].sva.fClusterStart)
1447 int j;
1448 for (j = 0; j < cChars; j++)
1450 if (pwLogClust[j] == i)
1452 int k = j;
1453 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1454 k-=1;
1455 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1456 pwLogClust[j] = pwLogClust[k];
1463 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1465 if (changeCount == 0)
1466 return;
1467 else
1469 int i;
1470 int target_glyph = nextIndex - write_dir;
1471 int seeking_glyph;
1472 int target_index = -1;
1473 int replacing_glyph = -1;
1474 int changed = 0;
1475 int top_logclust = 0;
1477 if (changeCount > 0)
1479 if (write_dir > 0)
1480 target_glyph = nextIndex - changeCount;
1481 else
1482 target_glyph = nextIndex + (changeCount + 1);
1485 seeking_glyph = target_glyph;
1486 for (i = 0; i < chars; i++)
1487 if (pwLogClust[i] > top_logclust)
1488 top_logclust = pwLogClust[i];
1490 do {
1491 if (write_dir > 0)
1492 for (i = 0; i < chars; i++)
1494 if (pwLogClust[i] == seeking_glyph)
1496 target_index = i;
1497 break;
1500 else
1501 for (i = chars - 1; i >= 0; i--)
1503 if (pwLogClust[i] == seeking_glyph)
1505 target_index = i;
1506 break;
1509 if (target_index == -1)
1510 seeking_glyph ++;
1512 while (target_index == -1 && seeking_glyph <= top_logclust);
1514 if (target_index == -1)
1516 ERR("Unable to find target glyph\n");
1517 return;
1520 if (changeCount < 0)
1522 /* merge glyphs */
1523 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1525 if (pwLogClust[i] == target_glyph)
1526 continue;
1527 if(pwLogClust[i] == replacing_glyph)
1528 pwLogClust[i] = target_glyph;
1529 else
1531 changed--;
1532 if (changed >= changeCount)
1534 replacing_glyph = pwLogClust[i];
1535 pwLogClust[i] = target_glyph;
1537 else
1538 break;
1542 /* renumber trailing indexes*/
1543 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1545 if (pwLogClust[i] != target_glyph)
1546 pwLogClust[i] += changeCount;
1549 else
1551 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1552 pwLogClust[i] += changeCount;
1557 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 )
1559 if (psc->GSUB_Table)
1561 const GSUB_Feature *feature;
1562 const GSUB_LookupList *lookup;
1563 const GSUB_Header *header = psc->GSUB_Table;
1564 int lookup_index, lookup_count;
1566 feature = load_GSUB_feature(hdc, psa, psc, feat);
1567 if (!feature)
1568 return GSUB_E_NOFEATURE;
1570 TRACE("applying feature %s\n",debugstr_an(feat,4));
1571 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1572 lookup_count = GET_BE_WORD(feature->LookupCount);
1573 TRACE("%i lookups\n", lookup_count);
1574 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1576 int i;
1578 if (write_dir > 0)
1579 i = 0;
1580 else
1581 i = *pcGlyphs-1;
1582 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1583 while(i < *pcGlyphs && i >= 0)
1585 INT nextIndex;
1586 INT prevCount = *pcGlyphs;
1588 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1589 if (*pcGlyphs != prevCount)
1591 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1592 i = nextIndex;
1594 else
1595 i+=write_dir;
1598 return *pcGlyphs;
1600 return GSUB_E_NOFEATURE;
1603 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1605 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1608 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1610 if (i + delta < 0)
1611 return 0;
1612 if ( i+ delta >= cchLen)
1613 return 0;
1615 i += delta;
1617 return chars[i];
1620 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1622 if (i + delta < 0)
1624 if (psa->fLinkBefore)
1625 return jtR;
1626 else
1627 return jtU;
1629 if ( i+ delta >= cchLen)
1631 if (psa->fLinkAfter)
1632 return jtL;
1633 else
1634 return jtU;
1637 i += delta;
1639 if (context_type[i] == jtT)
1640 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1641 else
1642 return context_type[i];
1645 static inline BOOL right_join_causing(CHAR joining_type)
1647 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1650 static inline BOOL left_join_causing(CHAR joining_type)
1652 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1655 static inline BOOL word_break_causing(WCHAR chr)
1657 /* we are working within a string of characters already guareented to
1658 be within one script, Syriac, so we do not worry about any character
1659 other than the space character outside of that range */
1660 return (chr == 0 || chr == 0x20 );
1664 * ContextualShape_Arabic
1666 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1668 CHAR *context_type;
1669 INT *context_shape;
1670 INT dirR, dirL;
1671 int i;
1673 if (*pcGlyphs != cChars)
1675 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1676 return;
1679 if (!psa->fLogicalOrder && psa->fRTL)
1681 dirR = 1;
1682 dirL = -1;
1684 else
1686 dirR = -1;
1687 dirL = 1;
1690 if (!psc->GSUB_Table)
1691 psc->GSUB_Table = load_gsub_table(hdc);
1693 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1694 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1696 for (i = 0; i < cChars; i++)
1697 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1699 for (i = 0; i < cChars; i++)
1701 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1702 context_shape[i] = Xr;
1703 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1704 context_shape[i] = Xl;
1705 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)))
1706 context_shape[i] = Xm;
1707 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1708 context_shape[i] = Xr;
1709 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1710 context_shape[i] = Xl;
1711 else
1712 context_shape[i] = Xn;
1715 /* Contextual Shaping */
1716 i = 0;
1717 while(i < *pcGlyphs)
1719 BOOL shaped = FALSE;
1721 if (psc->GSUB_Table)
1723 INT nextIndex;
1724 INT prevCount = *pcGlyphs;
1725 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1726 if (nextIndex > GSUB_E_NOGLYPH)
1728 i = nextIndex;
1729 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1731 shaped = (nextIndex > GSUB_E_NOGLYPH);
1734 if (!shaped)
1736 if (context_shape[i] == Xn)
1738 WORD newGlyph = pwOutGlyphs[i];
1739 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1741 /* fall back to presentation form B */
1742 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1743 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1744 pwOutGlyphs[i] = newGlyph;
1747 i++;
1751 HeapFree(GetProcessHeap(),0,context_shape);
1752 HeapFree(GetProcessHeap(),0,context_type);
1756 * ContextualShape_Syriac
1759 #define ALAPH 0x710
1760 #define DALATH 0x715
1761 #define RISH 0x72A
1763 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1765 CHAR *context_type;
1766 INT *context_shape;
1767 INT dirR, dirL;
1768 int i;
1770 if (*pcGlyphs != cChars)
1772 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1773 return;
1776 if (!psa->fLogicalOrder && psa->fRTL)
1778 dirR = 1;
1779 dirL = -1;
1781 else
1783 dirR = -1;
1784 dirL = 1;
1787 if (!psc->GSUB_Table)
1788 psc->GSUB_Table = load_gsub_table(hdc);
1790 if (!psc->GSUB_Table)
1791 return;
1793 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1794 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1796 for (i = 0; i < cChars; i++)
1797 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1799 for (i = 0; i < cChars; i++)
1801 if (pwcChars[i] == ALAPH)
1803 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1805 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1806 context_shape[i] = Afj;
1807 else if ( rchar != DALATH && rchar != RISH &&
1808 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1809 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1810 context_shape[i] = Afn;
1811 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1812 context_shape[i] = Afx;
1813 else
1814 context_shape[i] = Xn;
1816 else if (context_type[i] == jtR &&
1817 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1818 context_shape[i] = Xr;
1819 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1820 context_shape[i] = Xl;
1821 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)))
1822 context_shape[i] = Xm;
1823 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1824 context_shape[i] = Xr;
1825 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1826 context_shape[i] = Xl;
1827 else
1828 context_shape[i] = Xn;
1831 /* Contextual Shaping */
1832 i = 0;
1833 while(i < *pcGlyphs)
1835 INT nextIndex;
1836 INT prevCount = *pcGlyphs;
1837 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1838 if (nextIndex > GSUB_E_NOGLYPH)
1840 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1841 i = nextIndex;
1843 else
1844 i++;
1847 HeapFree(GetProcessHeap(),0,context_shape);
1848 HeapFree(GetProcessHeap(),0,context_type);
1852 * ContextualShape_Phags_pa
1855 #define phags_pa_CANDRABINDU 0xA873
1856 #define phags_pa_START 0xA840
1857 #define phags_pa_END 0xA87F
1859 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1861 INT *context_shape;
1862 INT dirR, dirL;
1863 int i;
1865 if (*pcGlyphs != cChars)
1867 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1868 return;
1871 if (!psa->fLogicalOrder && psa->fRTL)
1873 dirR = 1;
1874 dirL = -1;
1876 else
1878 dirR = -1;
1879 dirL = 1;
1882 if (!psc->GSUB_Table)
1883 psc->GSUB_Table = load_gsub_table(hdc);
1885 if (!psc->GSUB_Table)
1886 return;
1888 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1890 for (i = 0; i < cChars; i++)
1892 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1894 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1895 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1896 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1897 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1899 if (jrchar && jlchar)
1900 context_shape[i] = Xm;
1901 else if (jrchar)
1902 context_shape[i] = Xr;
1903 else if (jlchar)
1904 context_shape[i] = Xl;
1905 else
1906 context_shape[i] = Xn;
1908 else
1909 context_shape[i] = -1;
1912 /* Contextual Shaping */
1913 i = 0;
1914 while(i < *pcGlyphs)
1916 if (context_shape[i] >= 0)
1918 INT nextIndex;
1919 INT prevCount = *pcGlyphs;
1920 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1921 if (nextIndex > GSUB_E_NOGLYPH)
1923 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1924 i = nextIndex;
1926 else
1927 i++;
1929 else
1930 i++;
1933 HeapFree(GetProcessHeap(),0,context_shape);
1936 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1938 int i;
1940 /* Replace */
1941 pwOutChars[cWalk] = replacements[0];
1942 cWalk=cWalk+1;
1944 /* Insert */
1945 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1947 int j;
1948 for (j = *pcChars; j > cWalk; j--)
1949 pwOutChars[j] = pwOutChars[j-1];
1950 *pcChars= *pcChars+1;
1951 pwOutChars[cWalk] = replacements[i];
1952 cWalk = cWalk+1;
1956 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1958 int i;
1959 int cWalk;
1961 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1963 for (i = 0; vowels[i].base != 0x0; i++)
1965 if (pwOutChars[cWalk] == vowels[i].base)
1967 int o = 0;
1968 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1969 if (vowels[i].parts[1]) { cWalk++; o++; }
1970 if (vowels[i].parts[2]) { cWalk++; o++; }
1971 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1972 break;
1978 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1980 int i;
1981 int offset = 0;
1982 int cWalk;
1984 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1986 for (i = 0; consonants[i].output!= 0x0; i++)
1988 int j;
1989 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1990 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1991 break;
1993 if (consonants[i].parts[j]==0x0) /* matched all */
1995 int k;
1996 j--;
1997 pwOutChars[cWalk] = consonants[i].output;
1998 for(k = cWalk+1; k < *pcChars - j; k++)
1999 pwOutChars[k] = pwOutChars[k+j];
2000 *pcChars = *pcChars - j;
2001 for (k = j ; k > 0; k--)
2002 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
2003 offset += j;
2004 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
2005 pwLogClust[k]--;
2006 break;
2009 cWalk++;
2013 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2015 if (s->ralf >= 0)
2017 int j;
2018 WORD Ra = pwChar[s->start];
2019 WORD H = pwChar[s->start+1];
2021 TRACE("Doing reorder of Ra to %i\n",s->base);
2022 for (j = s->start; j < s->base-1; j++)
2023 pwChar[j] = pwChar[j+2];
2024 pwChar[s->base-1] = Ra;
2025 pwChar[s->base] = H;
2027 s->ralf = s->base-1;
2028 s->base -= 2;
2032 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2034 if (s->ralf >= 0)
2036 int j,loc;
2037 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
2038 WORD Ra = pwChar[s->start];
2039 WORD H = pwChar[s->start+1];
2040 for (loc = s->end; loc > stop; loc--)
2041 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
2042 break;
2044 TRACE("Doing reorder of Ra to %i\n",loc);
2045 for (j = s->start; j < loc-1; j++)
2046 pwChar[j] = pwChar[j+2];
2047 pwChar[loc-1] = Ra;
2048 pwChar[loc] = H;
2050 s->ralf = loc-1;
2051 s->base -= 2;
2052 if (s->blwf >= 0) s->blwf -= 2;
2053 if (s->pref >= 0) s->pref -= 2;
2057 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2059 if (s->ralf >= 0)
2061 int j;
2062 WORD Ra = pwChar[s->start];
2063 WORD H = pwChar[s->start+1];
2065 TRACE("Doing reorder of Ra to %i\n",s->end-1);
2066 for (j = s->start; j < s->end-1; j++)
2067 pwChar[j] = pwChar[j+2];
2068 pwChar[s->end-1] = Ra;
2069 pwChar[s->end] = H;
2071 s->ralf = s->end-1;
2072 s->base -= 2;
2073 if (s->blwf >= 0) s->blwf -= 2;
2074 if (s->pref >= 0) s->pref -= 2;
2078 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2080 int i;
2082 /* reorder Matras */
2083 if (s->end > s->base)
2085 for (i = 1; i <= s->end-s->base; i++)
2087 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2089 int j;
2090 WCHAR c = pwChar[s->base+i];
2091 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
2092 for (j = s->base+i; j > s->base; j--)
2093 pwChar[j] = pwChar[j-1];
2094 pwChar[s->base] = c;
2096 if (s->ralf >= s->base) s->ralf++;
2097 if (s->blwf >= s->base) s->blwf++;
2098 if (s->pref >= s->base) s->pref++;
2099 s->base ++;
2105 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2107 int i;
2109 /* reorder Matras */
2110 if (s->end > s->base)
2112 for (i = 1; i <= s->end-s->base; i++)
2114 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2116 int j;
2117 WCHAR c = pwChar[s->base+i];
2118 TRACE("Doing reorder of %x to %i\n",c,s->start);
2119 for (j = s->base+i; j > s->start; j--)
2120 pwChar[j] = pwChar[j-1];
2121 pwChar[s->start] = c;
2123 if (s->ralf >= 0) s->ralf++;
2124 if (s->blwf >= 0) s->blwf++;
2125 if (s->pref >= 0) s->pref++;
2126 s->base ++;
2132 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2134 if (s->blwf >= 0 && g->blwf > g->base)
2136 int j,loc;
2137 int g_offset;
2138 for (loc = s->end; loc > s->blwf; loc--)
2139 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2140 break;
2142 g_offset = (loc - s->blwf) - 1;
2144 if (loc != s->blwf)
2146 WORD blwf = glyphs[g->blwf];
2147 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2148 /* do not care about the pwChar array anymore, just the glyphs */
2149 for (j = 0; j < g_offset; j++)
2150 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2151 glyphs[g->blwf + g_offset] = blwf;
2156 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2158 int i;
2160 /* reorder previously moved Matras to correct position*/
2161 for (i = s->start; i < s->base; i++)
2163 if (lexical(pwChar[i]) == lex_Matra_pre)
2165 int j;
2166 int g_start = g->start + i - s->start;
2167 if (g_start < g->base -1 )
2169 WCHAR og = glyphs[g_start];
2170 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2171 for (j = g_start; j < g->base-1; j++)
2172 glyphs[j] = glyphs[j+1];
2173 glyphs[g->base-1] = og;
2179 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2181 if (s->pref >= 0 && g->pref > g->base)
2183 int j;
2184 WCHAR og = glyphs[g->pref];
2185 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2186 for (j = g->pref; j > g->base; j--)
2187 glyphs[j] = glyphs[j-1];
2188 glyphs[g->base] = og;
2192 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2194 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2195 if (s->start == s->base && s->base == s->end) return;
2196 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2198 Reorder_Ra_follows_base(pwChar, s, lexical);
2199 Reorder_Matra_precede_base(pwChar, s, lexical);
2202 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2204 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2205 if (s->start == s->base && s->base == s->end) return;
2206 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2208 Reorder_Ra_follows_matra(pwChar, s, lexical);
2209 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2212 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2214 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2215 if (s->start == s->base && s->base == s->end) return;
2216 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2218 Reorder_Ra_follows_base(pwChar, s, lexical);
2219 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2222 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2224 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2225 if (s->start == s->base && s->base == s->end) return;
2226 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2228 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2229 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2232 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2234 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2235 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2236 if (s->start == s->base && s->base == s->end) return;
2237 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2239 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2242 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2244 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2245 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2246 if (s->start == s->base && s->base == s->end) return;
2247 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2249 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2250 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2254 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2256 if (shift == 0)
2257 return;
2259 if (glyph_index->start > index)
2260 glyph_index->start += shift;
2261 if (glyph_index->base > index)
2262 glyph_index->base+= shift;
2263 if (glyph_index->end > index)
2264 glyph_index->end+= shift;
2265 if (glyph_index->ralf > index)
2266 glyph_index->ralf+= shift;
2267 if (glyph_index->blwf > index)
2268 glyph_index->blwf+= shift;
2269 if (glyph_index->pref > index)
2270 glyph_index->pref+= shift;
2273 static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const GSUB_Feature *feature )
2275 int index = glyph_index->start;
2277 if (!feature)
2278 return;
2280 while(index <= glyph_index->end)
2282 INT nextIndex;
2283 INT prevCount = *pcGlyphs;
2284 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2285 if (nextIndex > GSUB_E_NOGLYPH)
2287 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2288 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2289 index = nextIndex;
2291 else
2292 index++;
2296 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2298 int i = 0;
2299 while (i + index < end - 1 && !(is_consonant(lexical(pwChars[index+i])) && (lexical(pwChars[index+i+1]) == lex_Halant || (index + i < end - 2 && lexical(pwChars[index+i+1]) == lex_Nukta && lexical(pwChars[index+i+2] == lex_Halant)))))
2300 i++;
2301 if (index + i <= end-1)
2302 return index + i;
2303 else
2304 return -1;
2307 static void Apply_Indic_PreBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const char* feature)
2309 INT index, nextIndex;
2310 INT count,g_offset;
2312 count = syllable->base - syllable->start;
2314 g_offset = 0;
2315 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2316 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2318 INT prevCount = *pcGlyphs;
2319 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2320 if (nextIndex > GSUB_E_NOGLYPH)
2322 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2323 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2324 g_offset += (*pcGlyphs - prevCount);
2327 index+=2;
2328 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2332 static void Apply_Indic_Rphf(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index)
2334 INT nextIndex;
2335 INT prevCount = *pcGlyphs;
2337 if (syllable->ralf >= 0)
2339 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2340 if (nextIndex > GSUB_E_NOGLYPH)
2342 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2343 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2348 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2350 int i = 0;
2351 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2352 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2353 is_consonant(lexical(pwChars[index+i+1])))))
2354 i++;
2355 if (index + i <= end-1)
2356 return index+i;
2357 else
2358 return -1;
2361 static void Apply_Indic_PostBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, BOOL modern, const char* feat)
2363 INT index, nextIndex;
2364 INT count, g_offset=0;
2365 INT ralf = syllable->ralf;
2367 count = syllable->end - syllable->base;
2369 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2371 while (index >= 0)
2373 INT prevCount = *pcGlyphs;
2374 if (ralf >=0 && ralf < index)
2376 g_offset--;
2377 ralf = -1;
2380 if (!modern)
2382 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2383 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2384 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2387 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2388 if (nextIndex > GSUB_E_NOGLYPH)
2390 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2391 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2392 g_offset += (*pcGlyphs - prevCount);
2394 else if (!modern)
2396 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2397 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2398 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2401 index+=2;
2402 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2406 static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllables, INT syllable_count, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, second_reorder_function second_reorder, BOOL modern)
2408 int c;
2409 int overall_shift = 0;
2410 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2411 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2412 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2413 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2414 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2415 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2416 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2417 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2418 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2419 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2420 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2421 IndicSyllable glyph_indexs;
2423 for (c = 0; c < syllable_count; c++)
2425 int old_end;
2426 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2427 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2428 old_end = glyph_indexs.end;
2430 if (locl)
2432 TRACE("applying feature locl\n");
2433 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2435 if (nukt)
2437 TRACE("applying feature nukt\n");
2438 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2440 if (akhn)
2442 TRACE("applying feature akhn\n");
2443 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2446 if (rphf)
2447 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2448 if (rkrf)
2450 TRACE("applying feature rkrf\n");
2451 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2453 if (pref)
2454 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2455 if (blwf)
2457 if (!modern)
2458 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2460 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2463 if (half)
2464 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2465 if (pstf)
2467 TRACE("applying feature pstf\n");
2468 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2470 if (vatu)
2472 TRACE("applying feature vatu\n");
2473 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2475 if (cjct)
2477 TRACE("applying feature cjct\n");
2478 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2481 if (second_reorder)
2482 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2484 overall_shift += glyph_indexs.end - old_end;
2488 static inline int unicode_lex(WCHAR c)
2490 int type;
2492 if (!c) return lex_Generic;
2493 if (c == 0x200D) return lex_ZWJ;
2494 if (c == 0x200C) return lex_ZWNJ;
2495 if (c == 0x00A0) return lex_NBSP;
2497 type = get_table_entry( indic_syllabic_table, c );
2499 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2501 switch( type )
2503 case 0x0d07: /* Unknown */
2504 case 0x0e07: /* Unknwon */
2505 default: return lex_Generic;
2506 case 0x0001:
2507 case 0x0002:
2508 case 0x0011:
2509 case 0x0012:
2510 case 0x0013:
2511 case 0x0014: return lex_Modifier;
2512 case 0x0003:
2513 case 0x0009:
2514 case 0x000a:
2515 case 0x000b:
2516 case 0x000d:
2517 case 0x000e:
2518 case 0x000f:
2519 case 0x0010: return lex_Consonant;
2520 case 0x0004: return lex_Nukta;
2521 case 0x0005: return lex_Halant;
2522 case 0x0006:
2523 case 0x0008: return lex_Vowel;
2524 case 0x0007:
2525 case 0x0107: return lex_Matra_post;
2526 case 0x0207:
2527 case 0x0307: return lex_Matra_pre;
2528 case 0x0807:
2529 case 0x0907:
2530 case 0x0a07:
2531 case 0x0b07:
2532 case 0x0c07:
2533 case 0x0407: return lex_Composed_Vowel;
2534 case 0x0507: return lex_Matra_above;
2535 case 0x0607: return lex_Matra_below;
2536 case 0x000c: return lex_Ra;
2540 static int sinhala_lex(WCHAR c)
2542 switch (c)
2544 case 0x0DDA:
2545 case 0x0DDD:
2546 case 0x0DDC:
2547 case 0x0DDE: return lex_Matra_post;
2548 default:
2549 return unicode_lex(c);
2553 static const VowelComponents Sinhala_vowels[] = {
2554 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2555 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2556 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2557 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2558 {0x0000, {0x0000,0x0000,0x0}}};
2560 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2562 int cCount = cChars;
2563 int i;
2564 WCHAR *input;
2565 IndicSyllable *syllables = NULL;
2566 int syllable_count = 0;
2568 if (*pcGlyphs != cChars)
2570 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2571 return;
2574 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2576 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2578 /* Step 1: Decompose multi part vowels */
2579 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2581 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2583 /* Step 2: Reorder within Syllables */
2584 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2585 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2587 /* Step 3: Strip dangling joiners */
2588 for (i = 0; i < cCount; i++)
2590 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2591 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2592 input[i] = 0x0020;
2595 /* Step 4: Base Form application to syllables */
2596 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2597 *pcGlyphs = cCount;
2598 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2600 HeapFree(GetProcessHeap(),0,input);
2601 HeapFree(GetProcessHeap(),0,syllables);
2604 static int devanagari_lex(WCHAR c)
2606 switch (c)
2608 case 0x0930: return lex_Ra;
2609 default:
2610 return unicode_lex(c);
2614 static const ConsonantComponents Devanagari_consonants[] ={
2615 {{0x0928, 0x093C, 0x00000}, 0x0929},
2616 {{0x0930, 0x093C, 0x00000}, 0x0931},
2617 {{0x0933, 0x093C, 0x00000}, 0x0934},
2618 {{0x0915, 0x093C, 0x00000}, 0x0958},
2619 {{0x0916, 0x093C, 0x00000}, 0x0959},
2620 {{0x0917, 0x093C, 0x00000}, 0x095A},
2621 {{0x091C, 0x093C, 0x00000}, 0x095B},
2622 {{0x0921, 0x093C, 0x00000}, 0x095C},
2623 {{0x0922, 0x093C, 0x00000}, 0x095D},
2624 {{0x092B, 0x093C, 0x00000}, 0x095E},
2625 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2627 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2629 int cCount = cChars;
2630 WCHAR *input;
2631 IndicSyllable *syllables = NULL;
2632 int syllable_count = 0;
2633 BOOL modern = get_GSUB_Indic2(psa, psc);
2635 if (*pcGlyphs != cChars)
2637 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2638 return;
2641 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2642 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2644 /* Step 1: Compose Consonant and Nukta */
2645 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2646 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2648 /* Step 2: Reorder within Syllables */
2649 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2650 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2651 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2652 *pcGlyphs = cCount;
2654 /* Step 3: Base Form application to syllables */
2655 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2657 HeapFree(GetProcessHeap(),0,input);
2658 HeapFree(GetProcessHeap(),0,syllables);
2661 static int bengali_lex(WCHAR c)
2663 switch (c)
2665 case 0x09B0: return lex_Ra;
2666 default:
2667 return unicode_lex(c);
2671 static const VowelComponents Bengali_vowels[] = {
2672 {0x09CB, {0x09C7,0x09BE,0x0000}},
2673 {0x09CC, {0x09C7,0x09D7,0x0000}},
2674 {0x0000, {0x0000,0x0000,0x0000}}};
2676 static const ConsonantComponents Bengali_consonants[] = {
2677 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2678 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2679 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2680 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2681 {{0x0000,0x0000,0x0000}, 0x0000}};
2683 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2685 int cCount = cChars;
2686 WCHAR *input;
2687 IndicSyllable *syllables = NULL;
2688 int syllable_count = 0;
2689 BOOL modern = get_GSUB_Indic2(psa, psc);
2691 if (*pcGlyphs != cChars)
2693 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2694 return;
2697 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2698 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2700 /* Step 1: Decompose Vowels and Compose Consonents */
2701 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2702 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2703 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2705 /* Step 2: Reorder within Syllables */
2706 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2707 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2708 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2709 *pcGlyphs = cCount;
2711 /* Step 3: Initial form is only applied to the beginning of words */
2712 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2714 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2716 int index = cCount;
2717 int gCount = 1;
2718 if (index > 0) index++;
2720 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2724 /* Step 4: Base Form application to syllables */
2725 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2727 HeapFree(GetProcessHeap(),0,input);
2728 HeapFree(GetProcessHeap(),0,syllables);
2731 static int gurmukhi_lex(WCHAR c)
2733 if (c == 0x0A71)
2734 return lex_Modifier;
2735 else
2736 return unicode_lex(c);
2739 static const ConsonantComponents Gurmukhi_consonants[] = {
2740 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2741 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2742 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2743 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2744 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2745 {{0x0000,0x0000,0x0000}, 0x0000}};
2747 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2749 int cCount = cChars;
2750 WCHAR *input;
2751 IndicSyllable *syllables = NULL;
2752 int syllable_count = 0;
2753 BOOL modern = get_GSUB_Indic2(psa, psc);
2755 if (*pcGlyphs != cChars)
2757 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2758 return;
2761 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2762 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2764 /* Step 1: Compose Consonents */
2765 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2766 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2768 /* Step 2: Reorder within Syllables */
2769 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2770 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2771 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2772 *pcGlyphs = cCount;
2774 /* Step 3: Base Form application to syllables */
2775 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2777 HeapFree(GetProcessHeap(),0,input);
2778 HeapFree(GetProcessHeap(),0,syllables);
2781 static int gujarati_lex(WCHAR c)
2783 switch (c)
2785 case 0x0AB0: return lex_Ra;
2786 default:
2787 return unicode_lex(c);
2791 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2793 int cCount = cChars;
2794 WCHAR *input;
2795 IndicSyllable *syllables = NULL;
2796 int syllable_count = 0;
2797 BOOL modern = get_GSUB_Indic2(psa, psc);
2799 if (*pcGlyphs != cChars)
2801 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2802 return;
2805 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2806 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2808 /* Step 1: Reorder within Syllables */
2809 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2810 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2811 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2812 *pcGlyphs = cCount;
2814 /* Step 2: Base Form application to syllables */
2815 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2817 HeapFree(GetProcessHeap(),0,input);
2818 HeapFree(GetProcessHeap(),0,syllables);
2821 static int oriya_lex(WCHAR c)
2823 switch (c)
2825 case 0x0B30: return lex_Ra;
2826 default:
2827 return unicode_lex(c);
2831 static const VowelComponents Oriya_vowels[] = {
2832 {0x0B48, {0x0B47,0x0B56,0x0000}},
2833 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2834 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2835 {0x0000, {0x0000,0x0000,0x0000}}};
2837 static const ConsonantComponents Oriya_consonants[] = {
2838 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2839 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2840 {{0x0000,0x0000,0x0000}, 0x0000}};
2842 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2844 int cCount = cChars;
2845 WCHAR *input;
2846 IndicSyllable *syllables = NULL;
2847 int syllable_count = 0;
2848 BOOL modern = get_GSUB_Indic2(psa, psc);
2850 if (*pcGlyphs != cChars)
2852 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2853 return;
2856 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2857 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2859 /* Step 1: Decompose Vowels and Compose Consonents */
2860 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2861 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2862 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2864 /* Step 2: Reorder within Syllables */
2865 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2866 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2867 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2868 *pcGlyphs = cCount;
2870 /* Step 3: Base Form application to syllables */
2871 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2873 HeapFree(GetProcessHeap(),0,input);
2874 HeapFree(GetProcessHeap(),0,syllables);
2877 static int tamil_lex(WCHAR c)
2879 return unicode_lex(c);
2882 static const VowelComponents Tamil_vowels[] = {
2883 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2884 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2885 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2886 {0x0000, {0x0000,0x0000,0x0000}}};
2888 static const ConsonantComponents Tamil_consonants[] = {
2889 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2890 {{0x0000,0x0000,0x0000}, 0x0000}};
2892 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2894 int cCount = cChars;
2895 WCHAR *input;
2896 IndicSyllable *syllables = NULL;
2897 int syllable_count = 0;
2898 BOOL modern = get_GSUB_Indic2(psa, psc);
2900 if (*pcGlyphs != cChars)
2902 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2903 return;
2906 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2907 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2909 /* Step 1: Decompose Vowels and Compose Consonents */
2910 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2911 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2912 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2914 /* Step 2: Reorder within Syllables */
2915 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2916 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2917 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2918 *pcGlyphs = cCount;
2920 /* Step 3: Base Form application to syllables */
2921 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2923 HeapFree(GetProcessHeap(),0,input);
2924 HeapFree(GetProcessHeap(),0,syllables);
2927 static int telugu_lex(WCHAR c)
2929 switch (c)
2931 case 0x0C43:
2932 case 0x0C44: return lex_Modifier;
2933 default:
2934 return unicode_lex(c);
2938 static const VowelComponents Telugu_vowels[] = {
2939 {0x0C48, {0x0C46,0x0C56,0x0000}},
2940 {0x0000, {0x0000,0x0000,0x0000}}};
2942 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2944 int cCount = cChars;
2945 WCHAR *input;
2946 IndicSyllable *syllables = NULL;
2947 int syllable_count = 0;
2948 BOOL modern = get_GSUB_Indic2(psa, psc);
2950 if (*pcGlyphs != cChars)
2952 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2953 return;
2956 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2957 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2959 /* Step 1: Decompose Vowels */
2960 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2961 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2963 /* Step 2: Reorder within Syllables */
2964 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2965 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2966 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2967 *pcGlyphs = cCount;
2969 /* Step 3: Base Form application to syllables */
2970 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2972 HeapFree(GetProcessHeap(),0,input);
2973 HeapFree(GetProcessHeap(),0,syllables);
2976 static int kannada_lex(WCHAR c)
2978 switch (c)
2980 case 0x0CB0: return lex_Ra;
2981 default:
2982 return unicode_lex(c);
2986 static const VowelComponents Kannada_vowels[] = {
2987 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2988 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2989 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2990 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2991 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2992 {0x0000, {0x0000,0x0000,0x0000}}};
2994 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2996 int cCount = cChars;
2997 WCHAR *input;
2998 IndicSyllable *syllables = NULL;
2999 int syllable_count = 0;
3000 BOOL modern = get_GSUB_Indic2(psa, psc);
3002 if (*pcGlyphs != cChars)
3004 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3005 return;
3008 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
3009 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3011 /* Step 1: Decompose Vowels */
3012 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
3013 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
3015 /* Step 2: Reorder within Syllables */
3016 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
3017 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3018 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3019 *pcGlyphs = cCount;
3021 /* Step 3: Base Form application to syllables */
3022 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
3024 HeapFree(GetProcessHeap(),0,input);
3025 HeapFree(GetProcessHeap(),0,syllables);
3028 static int malayalam_lex(WCHAR c)
3030 return unicode_lex(c);
3033 static const VowelComponents Malayalam_vowels[] = {
3034 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
3035 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
3036 {0x0D4C, {0x0D46,0x0D57,0x0000}},
3037 {0x0000, {0x0000,0x0000,0x0000}}};
3039 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3041 int cCount = cChars;
3042 WCHAR *input;
3043 IndicSyllable *syllables = NULL;
3044 int syllable_count = 0;
3045 BOOL modern = get_GSUB_Indic2(psa, psc);
3047 if (*pcGlyphs != cChars)
3049 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3050 return;
3053 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
3054 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3056 /* Step 1: Decompose Vowels */
3057 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
3058 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
3060 /* Step 2: Reorder within Syllables */
3061 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
3062 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3063 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3064 *pcGlyphs = cCount;
3066 /* Step 3: Base Form application to syllables */
3067 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
3069 HeapFree(GetProcessHeap(),0,input);
3070 HeapFree(GetProcessHeap(),0,syllables);
3073 static int khmer_lex(WCHAR c)
3075 return unicode_lex(c);
3078 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3080 int cCount = cChars;
3081 WCHAR *input;
3082 IndicSyllable *syllables = NULL;
3083 int syllable_count = 0;
3085 if (*pcGlyphs != cChars)
3087 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3088 return;
3091 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
3092 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3094 /* Step 1: Reorder within Syllables */
3095 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
3096 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3097 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3098 *pcGlyphs = cCount;
3100 /* Step 2: Base Form application to syllables */
3101 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
3103 HeapFree(GetProcessHeap(),0,input);
3104 HeapFree(GetProcessHeap(),0,syllables);
3107 static inline BOOL mongolian_wordbreak(WCHAR chr)
3109 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
3112 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3114 INT *context_shape;
3115 INT dirL;
3116 int i;
3118 if (*pcGlyphs != cChars)
3120 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3121 return;
3124 if (!psa->fLogicalOrder && psa->fRTL)
3125 dirL = -1;
3126 else
3127 dirL = 1;
3129 if (!psc->GSUB_Table)
3130 psc->GSUB_Table = load_gsub_table(hdc);
3132 if (!psc->GSUB_Table)
3133 return;
3135 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
3137 for (i = 0; i < cChars; i++)
3139 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
3141 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
3142 context_shape[i] = Xn;
3143 else
3144 context_shape[i] = Xl;
3146 else
3148 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
3149 context_shape[i] = Xr;
3150 else
3151 context_shape[i] = Xm;
3155 /* Contextual Shaping */
3156 i = 0;
3157 while(i < *pcGlyphs)
3159 INT nextIndex;
3160 INT prevCount = *pcGlyphs;
3161 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
3162 if (nextIndex > GSUB_E_NOGLYPH)
3164 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
3165 i = nextIndex;
3167 else
3168 i++;
3171 HeapFree(GetProcessHeap(),0,context_shape);
3174 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)
3176 int i,k;
3178 for (i = 0; i < cGlyphs; i++)
3180 int char_index[20];
3181 int char_count = 0;
3183 for (k = 0; k < cChars; k++)
3185 if (pwLogClust[k] == i)
3187 char_index[char_count] = k;
3188 char_count++;
3192 if (char_count == 0)
3193 continue;
3195 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3197 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3198 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3200 else
3201 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3204 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3205 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3208 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 )
3210 int i,k;
3211 int initGlyph, finaGlyph;
3212 INT dirR, dirL;
3213 BYTE *spaces;
3215 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3216 memset(spaces,0,cGlyphs);
3218 if (!psa->fLogicalOrder && psa->fRTL)
3220 initGlyph = cGlyphs-1;
3221 finaGlyph = 0;
3222 dirR = 1;
3223 dirL = -1;
3225 else
3227 initGlyph = 0;
3228 finaGlyph = cGlyphs-1;
3229 dirR = -1;
3230 dirL = 1;
3233 for (i = 0; i < cGlyphs; i++)
3235 for (k = 0; k < cChars; k++)
3236 if (pwLogClust[k] == i)
3238 if (pwcChars[k] == 0x0020)
3239 spaces[i] = 1;
3243 for (i = 0; i < cGlyphs; i++)
3245 int char_index[20];
3246 int char_count = 0;
3247 BOOL isInit, isFinal;
3249 for (k = 0; k < cChars; k++)
3251 if (pwLogClust[k] == i)
3253 char_index[char_count] = k;
3254 char_count++;
3258 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3259 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3261 if (char_count == 0)
3262 continue;
3264 if (char_count == 1)
3266 if (pwcChars[char_index[0]] == 0x0020) /* space */
3268 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3269 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3271 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3272 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3273 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3275 if (!isInit && !isFinal)
3276 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3277 else if (isInit)
3278 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3279 else
3280 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3282 else if (!isInit)
3284 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3285 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3286 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3287 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3288 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3289 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3290 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3291 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3292 else
3293 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3295 else if (!isInit && !isFinal)
3296 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3297 else
3298 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3300 else if (char_count == 2)
3302 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3303 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3304 else if (!isInit)
3305 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3306 else
3307 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3309 else if (!isInit && !isFinal)
3310 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3311 else
3312 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3315 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3316 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3317 HeapFree(GetProcessHeap(),0,spaces);
3320 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 )
3322 int i,k;
3323 int finaGlyph;
3324 INT dirL;
3325 BYTE *spaces;
3327 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3328 memset(spaces,0,cGlyphs);
3330 if (!psa->fLogicalOrder && psa->fRTL)
3332 finaGlyph = 0;
3333 dirL = -1;
3335 else
3337 finaGlyph = cGlyphs-1;
3338 dirL = 1;
3341 for (i = 0; i < cGlyphs; i++)
3343 for (k = 0; k < cChars; k++)
3344 if (pwLogClust[k] == i)
3346 if (pwcChars[k] == 0x0020)
3347 spaces[i] = 1;
3351 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3353 for (i = 0; i < cGlyphs; i++)
3355 int char_index[20];
3356 int char_count = 0;
3358 for (k = 0; k < cChars; k++)
3360 if (pwLogClust[k] == i)
3362 char_index[char_count] = k;
3363 char_count++;
3367 if (char_count == 0)
3368 continue;
3370 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3372 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3373 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3375 else if (i == finaGlyph)
3376 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3377 else
3378 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3380 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3381 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3382 pGlyphProp[i].sva.fClusterStart = 0;
3385 HeapFree(GetProcessHeap(),0,spaces);
3386 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3388 /* Do not allow justification between marks and their base */
3389 for (i = 0; i < cGlyphs; i++)
3391 if (!pGlyphProp[i].sva.fClusterStart)
3392 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3396 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)
3398 int i,k;
3400 for (i = 0; i < cGlyphs; i++)
3402 int char_index[20];
3403 int char_count = 0;
3405 for (k = 0; k < cChars; k++)
3407 if (pwLogClust[k] == i)
3409 char_index[char_count] = k;
3410 char_count++;
3414 if (char_count == 0)
3415 continue;
3417 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3419 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3420 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3422 else
3423 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3425 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3426 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3429 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)
3431 int i,k;
3433 for (i = 0; i < cGlyphs; i++)
3435 int char_index[20];
3436 int char_count = 0;
3438 for (k = 0; k < cChars; k++)
3440 if (pwLogClust[k] == i)
3442 char_index[char_count] = k;
3443 char_count++;
3447 if (char_count == 0)
3448 continue;
3450 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3452 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3453 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3455 else
3456 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3458 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3459 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3461 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3462 for (i = 0; i < cGlyphs; i++)
3464 if (!pGlyphProp[i].sva.fClusterStart)
3466 pGlyphProp[i].sva.fDiacritic = 0;
3467 pGlyphProp[i].sva.fZeroWidth = 0;
3472 static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables, BOOL override_gsub)
3474 int i,k;
3476 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3477 for (i = 0; i < cGlyphs; i++)
3479 int char_index[20];
3480 int char_count = 0;
3482 for (k = 0; k < cChars; k++)
3484 if (pwLogClust[k] == i)
3486 char_index[char_count] = k;
3487 char_count++;
3491 if (override_gsub)
3493 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3494 pGlyphProp[i].sva.fDiacritic = FALSE;
3495 pGlyphProp[i].sva.fZeroWidth = FALSE;
3498 if (char_count == 0)
3499 continue;
3501 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3503 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3504 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3506 else
3507 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3509 pGlyphProp[i].sva.fClusterStart = 0;
3510 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3511 switch (lexical(pwcChars[char_index[k]]))
3513 case lex_Matra_pre:
3514 case lex_Matra_post:
3515 case lex_Matra_above:
3516 case lex_Matra_below:
3517 case lex_Modifier:
3518 case lex_Halant:
3519 break;
3520 case lex_ZWJ:
3521 case lex_ZWNJ:
3522 /* check for dangling joiners */
3523 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3524 pGlyphProp[i].sva.fClusterStart = 1;
3525 else
3526 k = char_count;
3527 break;
3528 default:
3529 pGlyphProp[i].sva.fClusterStart = 1;
3530 break;
3534 if (use_syllables)
3536 IndicSyllable *syllables = NULL;
3537 int syllable_count = 0;
3538 BOOL modern = get_GSUB_Indic2(psa, psc);
3540 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3542 for (i = 0; i < syllable_count; i++)
3544 int j;
3545 WORD g = pwLogClust[syllables[i].start];
3546 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3548 if (pwLogClust[j] != g)
3550 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3551 pwLogClust[j] = g;
3556 HeapFree(GetProcessHeap(), 0, syllables);
3559 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3562 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3564 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3567 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 )
3569 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3572 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 )
3574 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3577 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 )
3579 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3582 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 )
3584 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3587 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 )
3589 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3592 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 )
3594 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3597 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 )
3599 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3602 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 )
3604 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3607 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp )
3609 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3612 static void ShapeCharGlyphProp_Khmer( 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 )
3614 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3617 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)
3619 if (ShapingData[psa->eScript].charGlyphPropProc)
3620 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3621 else
3622 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3625 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3627 if (!psc->GSUB_Table)
3628 psc->GSUB_Table = load_gsub_table(hdc);
3630 if (ShapingData[psa->eScript].contextProc)
3631 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3634 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)
3636 int i;
3637 INT dirL;
3639 if (!rpRangeProperties)
3640 return;
3642 if (!psc->GSUB_Table)
3643 psc->GSUB_Table = load_gsub_table(hdc);
3645 if (!psc->GSUB_Table)
3646 return;
3648 if (!psa->fLogicalOrder && psa->fRTL)
3649 dirL = -1;
3650 else
3651 dirL = 1;
3653 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3655 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3656 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3660 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3662 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3663 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3665 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3668 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3670 const GSUB_Feature *feature;
3671 int i;
3673 if (!ShapingData[psa->eScript].requiredFeatures)
3674 return S_OK;
3676 if (!psc->GSUB_Table)
3677 psc->GSUB_Table = load_gsub_table(hdc);
3679 /* we need to have at least one of the required features */
3680 i = 0;
3681 while (ShapingData[psa->eScript].requiredFeatures[i])
3683 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3684 if (feature)
3685 return S_OK;
3686 i++;
3689 return USP_E_SCRIPT_NOT_IN_FONT;
3692 static VOID *load_CMAP_format12_table(HDC hdc, ScriptCache *psc)
3694 CMAP_Header *CMAP_Table = NULL;
3695 int length;
3696 int i;
3698 if (!psc->CMAP_Table)
3700 length = GetFontData(hdc, CMAP_TAG , 0, NULL, 0);
3701 if (length != GDI_ERROR)
3703 psc->CMAP_Table = HeapAlloc(GetProcessHeap(),0,length);
3704 GetFontData(hdc, CMAP_TAG , 0, psc->CMAP_Table, length);
3705 TRACE("Loaded cmap table of %i bytes\n",length);
3707 else
3708 return NULL;
3711 CMAP_Table = psc->CMAP_Table;
3713 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
3715 if ( (GET_BE_WORD(CMAP_Table->tables[i].platformID) == 3) &&
3716 (GET_BE_WORD(CMAP_Table->tables[i].encodingID) == 10) )
3718 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
3719 if (GET_BE_WORD(format->format) == 12)
3720 return format;
3723 return NULL;
3726 static int compare_group(const void *a, const void* b)
3728 const DWORD *chr = a;
3729 const CMAP_SegmentedCoverage_group *group = b;
3731 if (*chr < GET_BE_DWORD(group->startCharCode))
3732 return -1;
3733 if (*chr > GET_BE_DWORD(group->endCharCode))
3734 return 1;
3735 return 0;
3738 DWORD CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags)
3740 /* BMP: use gdi32 for ease */
3741 if (utf32c < 0x10000)
3743 WCHAR ch = utf32c;
3744 return GetGlyphIndicesW(hdc,&ch, 1, pgi, flags);
3747 if (!psc->CMAP_format12_Table)
3748 psc->CMAP_format12_Table = load_CMAP_format12_table(hdc, psc);
3750 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
3751 *pgi = 0xffff;
3752 else
3753 *pgi = 0;
3755 if (psc->CMAP_format12_Table)
3757 CMAP_SegmentedCoverage *format = NULL;
3758 CMAP_SegmentedCoverage_group *group = NULL;
3760 format = (CMAP_SegmentedCoverage *)psc->CMAP_format12_Table;
3762 group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
3763 sizeof(CMAP_SegmentedCoverage_group), compare_group);
3765 if (group)
3767 DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
3768 *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
3769 return 0;
3772 return 0;