usp10: Add Osmanya script.
[wine/multimedia.git] / dlls / usp10 / shape.c
blobb234b115cd7d1eaa2c055f07626a85f8e92c98da
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},
714 {{ no_features, 0}, NULL, "dsrt", "", NULL, NULL},
715 {{ no_features, 0}, NULL, "osma", "", NULL, NULL},
716 {{ no_features, 0}, NULL, "osma", "", NULL, NULL},
719 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
721 const GSUB_CoverageFormat1* cf1;
723 cf1 = table;
725 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
727 int count = GET_BE_WORD(cf1->GlyphCount);
728 int i;
729 TRACE("Coverage Format 1, %i glyphs\n",count);
730 for (i = 0; i < count; i++)
731 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
732 return i;
733 return -1;
735 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
737 const GSUB_CoverageFormat2* cf2;
738 int i;
739 int count;
740 cf2 = (const GSUB_CoverageFormat2*)cf1;
742 count = GET_BE_WORD(cf2->RangeCount);
743 TRACE("Coverage Format 2, %i ranges\n",count);
744 for (i = 0; i < count; i++)
746 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
747 return -1;
748 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
749 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
751 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
752 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
755 return -1;
757 else
758 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
760 return -1;
763 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
765 const GSUB_ScriptList *script;
766 const GSUB_Script *deflt = NULL;
767 int i;
768 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
770 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
771 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
773 const GSUB_Script *scr;
774 int offset;
776 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
777 scr = (const GSUB_Script*)((const BYTE*)script + offset);
779 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
780 return scr;
781 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
782 deflt = scr;
784 return deflt;
787 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
789 int i;
790 int offset;
791 const GSUB_LangSys *Lang;
793 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
795 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
797 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
798 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
800 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
801 return Lang;
803 offset = GET_BE_WORD(script->DefaultLangSys);
804 if (offset)
806 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
807 return Lang;
809 return NULL;
812 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
814 int i;
815 const GSUB_FeatureList *feature;
816 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
818 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
819 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
821 int index = GET_BE_WORD(lang->FeatureIndex[i]);
822 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
824 const GSUB_Feature *feat;
825 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
826 return feat;
829 return NULL;
832 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
834 int j;
835 TRACE("Single Substitution Subtable\n");
837 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
839 int offset;
840 const GSUB_SingleSubstFormat1 *ssf1;
841 offset = GET_BE_WORD(look->SubTable[j]);
842 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
843 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
845 int offset = GET_BE_WORD(ssf1->Coverage);
846 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
847 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
849 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
850 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
851 TRACE(" 0x%x\n",glyphs[glyph_index]);
852 return glyph_index + write_dir;
855 else
857 const GSUB_SingleSubstFormat2 *ssf2;
858 INT index;
859 INT offset;
861 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
862 offset = GET_BE_WORD(ssf1->Coverage);
863 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
864 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
865 TRACE(" Coverage index %i\n",index);
866 if (index != -1)
868 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
869 return GSUB_E_NOGLYPH;
871 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
872 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
873 TRACE("0x%x\n",glyphs[glyph_index]);
874 return glyph_index + write_dir;
878 return GSUB_E_NOGLYPH;
881 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
883 int j;
884 TRACE("Multiple Substitution Subtable\n");
886 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
888 int offset, index;
889 const GSUB_MultipleSubstFormat1 *msf1;
890 offset = GET_BE_WORD(look->SubTable[j]);
891 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
893 offset = GET_BE_WORD(msf1->Coverage);
894 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
895 if (index != -1)
897 const GSUB_Sequence *seq;
898 int sub_count;
899 int j;
900 offset = GET_BE_WORD(msf1->Sequence[index]);
901 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
902 sub_count = GET_BE_WORD(seq->GlyphCount);
903 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
905 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
906 glyphs[j] =glyphs[j-(sub_count-1)];
908 for (j = 0; j < sub_count; j++)
909 if (write_dir < 0)
910 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
911 else
912 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
914 *glyph_count = *glyph_count + (sub_count - 1);
916 if (TRACE_ON(uniscribe))
918 for (j = 0; j < sub_count; j++)
919 TRACE(" 0x%x",glyphs[glyph_index+j]);
920 TRACE("\n");
923 return glyph_index + (sub_count * write_dir);
926 return GSUB_E_NOGLYPH;
929 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
931 int j;
932 TRACE("Alternate Substitution Subtable\n");
934 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
936 int offset;
937 const GSUB_AlternateSubstFormat1 *asf1;
938 INT index;
940 offset = GET_BE_WORD(look->SubTable[j]);
941 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
942 offset = GET_BE_WORD(asf1->Coverage);
944 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
945 if (index != -1)
947 const GSUB_AlternateSet *as;
948 offset = GET_BE_WORD(asf1->AlternateSet[index]);
949 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
950 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
951 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
952 return GSUB_E_NOGLYPH;
954 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
955 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
956 TRACE(" 0x%x\n",glyphs[glyph_index]);
957 return glyph_index + write_dir;
960 return GSUB_E_NOGLYPH;
963 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
965 int j;
967 TRACE("Ligature Substitution Subtable\n");
968 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
970 const GSUB_LigatureSubstFormat1 *lsf1;
971 int offset,index;
973 offset = GET_BE_WORD(look->SubTable[j]);
974 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
975 offset = GET_BE_WORD(lsf1->Coverage);
976 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
977 TRACE(" Coverage index %i\n",index);
978 if (index != -1)
980 const GSUB_LigatureSet *ls;
981 int k, count;
983 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
984 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
985 count = GET_BE_WORD(ls->LigatureCount);
986 TRACE(" LigatureSet has %i members\n",count);
987 for (k = 0; k < count; k++)
989 const GSUB_Ligature *lig;
990 int CompCount,l,CompIndex;
992 offset = GET_BE_WORD(ls->Ligature[k]);
993 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
994 CompCount = GET_BE_WORD(lig->CompCount) - 1;
995 CompIndex = glyph_index+write_dir;
996 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
998 int CompGlyph;
999 CompGlyph = GET_BE_WORD(lig->Component[l]);
1000 if (CompGlyph != glyphs[CompIndex])
1001 break;
1002 CompIndex += write_dir;
1004 if (l == CompCount)
1006 int replaceIdx = glyph_index;
1007 if (write_dir < 0)
1008 replaceIdx = glyph_index - CompCount;
1010 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
1011 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
1012 TRACE("0x%x\n",glyphs[replaceIdx]);
1013 if (CompCount > 0)
1015 int j;
1016 for (j = replaceIdx + 1; j < *glyph_count; j++)
1017 glyphs[j] =glyphs[j+CompCount];
1018 *glyph_count = *glyph_count - CompCount;
1020 return replaceIdx + write_dir;
1025 return GSUB_E_NOGLYPH;
1028 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1030 int j;
1031 BOOL done = FALSE;
1033 TRACE("Chaining Contextual Substitution Subtable\n");
1034 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
1036 const GSUB_ChainContextSubstFormat1 *ccsf1;
1037 int offset;
1038 int dirLookahead = write_dir;
1039 int dirBacktrack = -1 * write_dir;
1041 offset = GET_BE_WORD(look->SubTable[j]);
1042 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
1043 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
1045 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
1046 continue;
1048 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
1050 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
1051 continue;
1053 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
1055 int k;
1056 int indexGlyphs;
1057 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
1058 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
1059 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
1060 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
1061 int newIndex = glyph_index;
1063 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
1065 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
1067 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
1069 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
1070 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
1071 break;
1073 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
1074 continue;
1075 TRACE("Matched Backtrack\n");
1077 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
1079 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
1080 for (k = 0; k < indexGlyphs; k++)
1082 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
1083 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
1084 break;
1086 if (k != indexGlyphs)
1087 continue;
1088 TRACE("Matched IndexGlyphs\n");
1090 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
1092 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
1094 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
1095 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
1096 break;
1098 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
1099 continue;
1100 TRACE("Matched LookAhead\n");
1102 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
1104 if (GET_BE_WORD(ccsf3_4->SubstCount))
1106 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
1108 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
1109 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
1111 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
1112 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
1113 if (newIndex == -1)
1115 ERR("Chain failed to generate a glyph\n");
1116 continue;
1119 return newIndex;
1121 else return GSUB_E_NOGLYPH;
1124 return -1;
1127 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1129 int offset;
1130 const GSUB_LookupTable *look;
1132 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1133 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1134 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1135 switch(GET_BE_WORD(look->LookupType))
1137 case 1:
1138 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1139 case 2:
1140 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1141 case 3:
1142 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1143 case 4:
1144 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1145 case 6:
1146 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1147 default:
1148 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1150 return GSUB_E_NOGLYPH;
1153 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)
1155 int i;
1156 int out_index = GSUB_E_NOGLYPH;
1157 const GSUB_LookupList *lookup;
1159 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1161 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1162 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1164 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1165 if (out_index != GSUB_E_NOGLYPH)
1166 break;
1168 if (out_index == GSUB_E_NOGLYPH)
1169 TRACE("lookups found no glyphs\n");
1170 else
1172 int out2;
1173 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1174 if (out2!=GSUB_E_NOGLYPH)
1175 out_index = out2;
1177 return out_index;
1180 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1182 UINT charset;
1184 if (psc->userScript != 0)
1186 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1187 return ShapingData[psa->eScript].newOtTag;
1188 else
1189 return (char*)&psc->userScript;
1192 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1193 return ShapingData[psa->eScript].newOtTag;
1195 if (ShapingData[psa->eScript].otTag[0] != 0)
1196 return ShapingData[psa->eScript].otTag;
1199 * fall back to the font charset
1201 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1202 switch (charset)
1204 case ANSI_CHARSET: return "latn";
1205 case BALTIC_CHARSET: return "latn"; /* ?? */
1206 case CHINESEBIG5_CHARSET: return "hani";
1207 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1208 case GB2312_CHARSET: return "hani";
1209 case GREEK_CHARSET: return "grek";
1210 case HANGUL_CHARSET: return "hang";
1211 case RUSSIAN_CHARSET: return "cyrl";
1212 case SHIFTJIS_CHARSET: return "kana";
1213 case TURKISH_CHARSET: return "latn"; /* ?? */
1214 case VIETNAMESE_CHARSET: return "latn";
1215 case JOHAB_CHARSET: return "latn"; /* ?? */
1216 case ARABIC_CHARSET: return "arab";
1217 case HEBREW_CHARSET: return "hebr";
1218 case THAI_CHARSET: return "thai";
1219 default: return "latn";
1223 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1225 const GSUB_Feature *feature;
1226 const char* script;
1227 int i;
1229 script = get_opentype_script(hdc,psa,psc,FALSE);
1231 for (i = 0; i < psc->feature_count; i++)
1233 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1234 return psc->features[i].feature;
1237 feature = NULL;
1239 if (psc->GSUB_Table)
1241 const GSUB_Script *script;
1242 const GSUB_LangSys *language;
1243 int attempt = 2;
1247 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1248 attempt--;
1249 if (script)
1251 if (psc->userLang != 0)
1252 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1253 else
1254 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1255 if (language)
1256 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1258 } while(attempt && !feature);
1260 /* try in the default (latin) table */
1261 if (!feature)
1263 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1264 if (script)
1266 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1267 if (language)
1268 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1273 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1275 psc->feature_count++;
1277 if (psc->features)
1278 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1279 else
1280 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1282 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1283 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1284 psc->features[psc->feature_count - 1].feature = feature;
1285 return feature;
1288 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)
1290 const GSUB_Feature *feature;
1292 feature = load_GSUB_feature(hdc, psa, psc, feat);
1293 if (!feature)
1294 return GSUB_E_NOFEATURE;
1296 TRACE("applying feature %s\n",feat);
1297 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1300 static VOID *load_gsub_table(HDC hdc)
1302 VOID* GSUB_Table = NULL;
1303 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1304 if (length != GDI_ERROR)
1306 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1307 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1308 TRACE("Loaded GSUB table of %i bytes\n",length);
1310 return GSUB_Table;
1313 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)
1315 WORD *glyphs;
1316 INT glyph_count = count;
1317 INT rc;
1319 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1320 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1321 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1322 if (rc > GSUB_E_NOGLYPH)
1323 rc = count - glyph_count;
1324 else
1325 rc = 0;
1327 HeapFree(GetProcessHeap(),0,glyphs);
1328 return rc;
1331 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1333 int offset;
1334 WORD class = 0;
1335 const GDEF_ClassDefFormat1 *cf1;
1337 if (!header)
1338 return 0;
1340 offset = GET_BE_WORD(header->GlyphClassDef);
1341 if (!offset)
1342 return 0;
1344 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1345 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1347 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1349 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1350 if (index < GET_BE_WORD(cf1->GlyphCount))
1351 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1354 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1356 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1357 int i, top;
1358 top = GET_BE_WORD(cf2->ClassRangeCount);
1359 for (i = 0; i < top; i++)
1361 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1362 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1364 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1365 break;
1369 else
1370 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1372 return class;
1375 static VOID *load_gdef_table(HDC hdc)
1377 VOID* GDEF_Table = NULL;
1378 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1379 if (length != GDI_ERROR)
1381 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1382 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1383 TRACE("Loaded GDEF table of %i bytes\n",length);
1385 return GDEF_Table;
1388 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
1390 int i;
1392 if (!psc->GDEF_Table)
1393 psc->GDEF_Table = load_gdef_table(hdc);
1395 for (i = 0; i < cGlyphs; i++)
1397 WORD class;
1398 int char_count = 0;
1399 int k;
1401 for (k = 0; k < cChars; k++)
1402 if (pwLogClust[k] == i)
1403 char_count++;
1405 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1407 switch (class)
1409 case 0:
1410 case BaseGlyph:
1411 pGlyphProp[i].sva.fClusterStart = 1;
1412 pGlyphProp[i].sva.fDiacritic = 0;
1413 pGlyphProp[i].sva.fZeroWidth = 0;
1414 break;
1415 case LigatureGlyph:
1416 pGlyphProp[i].sva.fClusterStart = 1;
1417 pGlyphProp[i].sva.fDiacritic = 0;
1418 pGlyphProp[i].sva.fZeroWidth = 0;
1419 break;
1420 case MarkGlyph:
1421 pGlyphProp[i].sva.fClusterStart = 0;
1422 pGlyphProp[i].sva.fDiacritic = 1;
1423 pGlyphProp[i].sva.fZeroWidth = 1;
1424 break;
1425 case ComponentGlyph:
1426 pGlyphProp[i].sva.fClusterStart = 0;
1427 pGlyphProp[i].sva.fDiacritic = 0;
1428 pGlyphProp[i].sva.fZeroWidth = 0;
1429 break;
1430 default:
1431 ERR("Unknown glyph class %i\n",class);
1432 pGlyphProp[i].sva.fClusterStart = 1;
1433 pGlyphProp[i].sva.fDiacritic = 0;
1434 pGlyphProp[i].sva.fZeroWidth = 0;
1437 if (char_count == 0)
1438 pGlyphProp[i].sva.fClusterStart = 0;
1442 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1444 int i;
1446 for (i = 0; i < cGlyphs; i++)
1448 if (!pGlyphProp[i].sva.fClusterStart)
1450 int j;
1451 for (j = 0; j < cChars; j++)
1453 if (pwLogClust[j] == i)
1455 int k = j;
1456 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1457 k-=1;
1458 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1459 pwLogClust[j] = pwLogClust[k];
1466 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1468 if (changeCount == 0)
1469 return;
1470 else
1472 int i;
1473 int target_glyph = nextIndex - write_dir;
1474 int seeking_glyph;
1475 int target_index = -1;
1476 int replacing_glyph = -1;
1477 int changed = 0;
1478 int top_logclust = 0;
1480 if (changeCount > 0)
1482 if (write_dir > 0)
1483 target_glyph = nextIndex - changeCount;
1484 else
1485 target_glyph = nextIndex + (changeCount + 1);
1488 seeking_glyph = target_glyph;
1489 for (i = 0; i < chars; i++)
1490 if (pwLogClust[i] > top_logclust)
1491 top_logclust = pwLogClust[i];
1493 do {
1494 if (write_dir > 0)
1495 for (i = 0; i < chars; i++)
1497 if (pwLogClust[i] == seeking_glyph)
1499 target_index = i;
1500 break;
1503 else
1504 for (i = chars - 1; i >= 0; i--)
1506 if (pwLogClust[i] == seeking_glyph)
1508 target_index = i;
1509 break;
1512 if (target_index == -1)
1513 seeking_glyph ++;
1515 while (target_index == -1 && seeking_glyph <= top_logclust);
1517 if (target_index == -1)
1519 ERR("Unable to find target glyph\n");
1520 return;
1523 if (changeCount < 0)
1525 /* merge glyphs */
1526 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1528 if (pwLogClust[i] == target_glyph)
1529 continue;
1530 if(pwLogClust[i] == replacing_glyph)
1531 pwLogClust[i] = target_glyph;
1532 else
1534 changed--;
1535 if (changed >= changeCount)
1537 replacing_glyph = pwLogClust[i];
1538 pwLogClust[i] = target_glyph;
1540 else
1541 break;
1545 /* renumber trailing indexes*/
1546 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1548 if (pwLogClust[i] != target_glyph)
1549 pwLogClust[i] += changeCount;
1552 else
1554 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1555 pwLogClust[i] += changeCount;
1560 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 )
1562 if (psc->GSUB_Table)
1564 const GSUB_Feature *feature;
1565 const GSUB_LookupList *lookup;
1566 const GSUB_Header *header = psc->GSUB_Table;
1567 int lookup_index, lookup_count;
1569 feature = load_GSUB_feature(hdc, psa, psc, feat);
1570 if (!feature)
1571 return GSUB_E_NOFEATURE;
1573 TRACE("applying feature %s\n",debugstr_an(feat,4));
1574 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1575 lookup_count = GET_BE_WORD(feature->LookupCount);
1576 TRACE("%i lookups\n", lookup_count);
1577 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1579 int i;
1581 if (write_dir > 0)
1582 i = 0;
1583 else
1584 i = *pcGlyphs-1;
1585 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1586 while(i < *pcGlyphs && i >= 0)
1588 INT nextIndex;
1589 INT prevCount = *pcGlyphs;
1591 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1592 if (*pcGlyphs != prevCount)
1594 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1595 i = nextIndex;
1597 else
1598 i+=write_dir;
1601 return *pcGlyphs;
1603 return GSUB_E_NOFEATURE;
1606 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1608 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1611 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1613 if (i + delta < 0)
1614 return 0;
1615 if ( i+ delta >= cchLen)
1616 return 0;
1618 i += delta;
1620 return chars[i];
1623 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1625 if (i + delta < 0)
1627 if (psa->fLinkBefore)
1628 return jtR;
1629 else
1630 return jtU;
1632 if ( i+ delta >= cchLen)
1634 if (psa->fLinkAfter)
1635 return jtL;
1636 else
1637 return jtU;
1640 i += delta;
1642 if (context_type[i] == jtT)
1643 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1644 else
1645 return context_type[i];
1648 static inline BOOL right_join_causing(CHAR joining_type)
1650 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1653 static inline BOOL left_join_causing(CHAR joining_type)
1655 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1658 static inline BOOL word_break_causing(WCHAR chr)
1660 /* we are working within a string of characters already guareented to
1661 be within one script, Syriac, so we do not worry about any character
1662 other than the space character outside of that range */
1663 return (chr == 0 || chr == 0x20 );
1667 * ContextualShape_Arabic
1669 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1671 CHAR *context_type;
1672 INT *context_shape;
1673 INT dirR, dirL;
1674 int i;
1676 if (*pcGlyphs != cChars)
1678 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1679 return;
1682 if (!psa->fLogicalOrder && psa->fRTL)
1684 dirR = 1;
1685 dirL = -1;
1687 else
1689 dirR = -1;
1690 dirL = 1;
1693 if (!psc->GSUB_Table)
1694 psc->GSUB_Table = load_gsub_table(hdc);
1696 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1697 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1699 for (i = 0; i < cChars; i++)
1700 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1702 for (i = 0; i < cChars; i++)
1704 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1705 context_shape[i] = Xr;
1706 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1707 context_shape[i] = Xl;
1708 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)))
1709 context_shape[i] = Xm;
1710 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1711 context_shape[i] = Xr;
1712 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1713 context_shape[i] = Xl;
1714 else
1715 context_shape[i] = Xn;
1718 /* Contextual Shaping */
1719 i = 0;
1720 while(i < *pcGlyphs)
1722 BOOL shaped = FALSE;
1724 if (psc->GSUB_Table)
1726 INT nextIndex;
1727 INT prevCount = *pcGlyphs;
1728 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1729 if (nextIndex > GSUB_E_NOGLYPH)
1731 i = nextIndex;
1732 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1734 shaped = (nextIndex > GSUB_E_NOGLYPH);
1737 if (!shaped)
1739 if (context_shape[i] == Xn)
1741 WORD newGlyph = pwOutGlyphs[i];
1742 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1744 /* fall back to presentation form B */
1745 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1746 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1747 pwOutGlyphs[i] = newGlyph;
1750 i++;
1754 HeapFree(GetProcessHeap(),0,context_shape);
1755 HeapFree(GetProcessHeap(),0,context_type);
1759 * ContextualShape_Syriac
1762 #define ALAPH 0x710
1763 #define DALATH 0x715
1764 #define RISH 0x72A
1766 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1768 CHAR *context_type;
1769 INT *context_shape;
1770 INT dirR, dirL;
1771 int i;
1773 if (*pcGlyphs != cChars)
1775 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1776 return;
1779 if (!psa->fLogicalOrder && psa->fRTL)
1781 dirR = 1;
1782 dirL = -1;
1784 else
1786 dirR = -1;
1787 dirL = 1;
1790 if (!psc->GSUB_Table)
1791 psc->GSUB_Table = load_gsub_table(hdc);
1793 if (!psc->GSUB_Table)
1794 return;
1796 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1797 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1799 for (i = 0; i < cChars; i++)
1800 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1802 for (i = 0; i < cChars; i++)
1804 if (pwcChars[i] == ALAPH)
1806 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1808 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1809 context_shape[i] = Afj;
1810 else if ( rchar != DALATH && rchar != RISH &&
1811 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1812 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1813 context_shape[i] = Afn;
1814 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1815 context_shape[i] = Afx;
1816 else
1817 context_shape[i] = Xn;
1819 else if (context_type[i] == jtR &&
1820 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1821 context_shape[i] = Xr;
1822 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1823 context_shape[i] = Xl;
1824 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)))
1825 context_shape[i] = Xm;
1826 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1827 context_shape[i] = Xr;
1828 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1829 context_shape[i] = Xl;
1830 else
1831 context_shape[i] = Xn;
1834 /* Contextual Shaping */
1835 i = 0;
1836 while(i < *pcGlyphs)
1838 INT nextIndex;
1839 INT prevCount = *pcGlyphs;
1840 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1841 if (nextIndex > GSUB_E_NOGLYPH)
1843 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1844 i = nextIndex;
1846 else
1847 i++;
1850 HeapFree(GetProcessHeap(),0,context_shape);
1851 HeapFree(GetProcessHeap(),0,context_type);
1855 * ContextualShape_Phags_pa
1858 #define phags_pa_CANDRABINDU 0xA873
1859 #define phags_pa_START 0xA840
1860 #define phags_pa_END 0xA87F
1862 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1864 INT *context_shape;
1865 INT dirR, dirL;
1866 int i;
1868 if (*pcGlyphs != cChars)
1870 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1871 return;
1874 if (!psa->fLogicalOrder && psa->fRTL)
1876 dirR = 1;
1877 dirL = -1;
1879 else
1881 dirR = -1;
1882 dirL = 1;
1885 if (!psc->GSUB_Table)
1886 psc->GSUB_Table = load_gsub_table(hdc);
1888 if (!psc->GSUB_Table)
1889 return;
1891 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1893 for (i = 0; i < cChars; i++)
1895 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1897 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1898 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1899 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1900 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1902 if (jrchar && jlchar)
1903 context_shape[i] = Xm;
1904 else if (jrchar)
1905 context_shape[i] = Xr;
1906 else if (jlchar)
1907 context_shape[i] = Xl;
1908 else
1909 context_shape[i] = Xn;
1911 else
1912 context_shape[i] = -1;
1915 /* Contextual Shaping */
1916 i = 0;
1917 while(i < *pcGlyphs)
1919 if (context_shape[i] >= 0)
1921 INT nextIndex;
1922 INT prevCount = *pcGlyphs;
1923 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1924 if (nextIndex > GSUB_E_NOGLYPH)
1926 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1927 i = nextIndex;
1929 else
1930 i++;
1932 else
1933 i++;
1936 HeapFree(GetProcessHeap(),0,context_shape);
1939 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1941 int i;
1943 /* Replace */
1944 pwOutChars[cWalk] = replacements[0];
1945 cWalk=cWalk+1;
1947 /* Insert */
1948 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1950 int j;
1951 for (j = *pcChars; j > cWalk; j--)
1952 pwOutChars[j] = pwOutChars[j-1];
1953 *pcChars= *pcChars+1;
1954 pwOutChars[cWalk] = replacements[i];
1955 cWalk = cWalk+1;
1959 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1961 int i;
1962 int cWalk;
1964 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1966 for (i = 0; vowels[i].base != 0x0; i++)
1968 if (pwOutChars[cWalk] == vowels[i].base)
1970 int o = 0;
1971 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1972 if (vowels[i].parts[1]) { cWalk++; o++; }
1973 if (vowels[i].parts[2]) { cWalk++; o++; }
1974 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1975 break;
1981 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1983 int i;
1984 int offset = 0;
1985 int cWalk;
1987 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1989 for (i = 0; consonants[i].output!= 0x0; i++)
1991 int j;
1992 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1993 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1994 break;
1996 if (consonants[i].parts[j]==0x0) /* matched all */
1998 int k;
1999 j--;
2000 pwOutChars[cWalk] = consonants[i].output;
2001 for(k = cWalk+1; k < *pcChars - j; k++)
2002 pwOutChars[k] = pwOutChars[k+j];
2003 *pcChars = *pcChars - j;
2004 for (k = j ; k > 0; k--)
2005 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
2006 offset += j;
2007 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
2008 pwLogClust[k]--;
2009 break;
2012 cWalk++;
2016 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2018 if (s->ralf >= 0)
2020 int j;
2021 WORD Ra = pwChar[s->start];
2022 WORD H = pwChar[s->start+1];
2024 TRACE("Doing reorder of Ra to %i\n",s->base);
2025 for (j = s->start; j < s->base-1; j++)
2026 pwChar[j] = pwChar[j+2];
2027 pwChar[s->base-1] = Ra;
2028 pwChar[s->base] = H;
2030 s->ralf = s->base-1;
2031 s->base -= 2;
2035 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2037 if (s->ralf >= 0)
2039 int j,loc;
2040 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
2041 WORD Ra = pwChar[s->start];
2042 WORD H = pwChar[s->start+1];
2043 for (loc = s->end; loc > stop; loc--)
2044 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
2045 break;
2047 TRACE("Doing reorder of Ra to %i\n",loc);
2048 for (j = s->start; j < loc-1; j++)
2049 pwChar[j] = pwChar[j+2];
2050 pwChar[loc-1] = Ra;
2051 pwChar[loc] = H;
2053 s->ralf = loc-1;
2054 s->base -= 2;
2055 if (s->blwf >= 0) s->blwf -= 2;
2056 if (s->pref >= 0) s->pref -= 2;
2060 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2062 if (s->ralf >= 0)
2064 int j;
2065 WORD Ra = pwChar[s->start];
2066 WORD H = pwChar[s->start+1];
2068 TRACE("Doing reorder of Ra to %i\n",s->end-1);
2069 for (j = s->start; j < s->end-1; j++)
2070 pwChar[j] = pwChar[j+2];
2071 pwChar[s->end-1] = Ra;
2072 pwChar[s->end] = H;
2074 s->ralf = s->end-1;
2075 s->base -= 2;
2076 if (s->blwf >= 0) s->blwf -= 2;
2077 if (s->pref >= 0) s->pref -= 2;
2081 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2083 int i;
2085 /* reorder Matras */
2086 if (s->end > s->base)
2088 for (i = 1; i <= s->end-s->base; i++)
2090 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2092 int j;
2093 WCHAR c = pwChar[s->base+i];
2094 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
2095 for (j = s->base+i; j > s->base; j--)
2096 pwChar[j] = pwChar[j-1];
2097 pwChar[s->base] = c;
2099 if (s->ralf >= s->base) s->ralf++;
2100 if (s->blwf >= s->base) s->blwf++;
2101 if (s->pref >= s->base) s->pref++;
2102 s->base ++;
2108 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2110 int i;
2112 /* reorder Matras */
2113 if (s->end > s->base)
2115 for (i = 1; i <= s->end-s->base; i++)
2117 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2119 int j;
2120 WCHAR c = pwChar[s->base+i];
2121 TRACE("Doing reorder of %x to %i\n",c,s->start);
2122 for (j = s->base+i; j > s->start; j--)
2123 pwChar[j] = pwChar[j-1];
2124 pwChar[s->start] = c;
2126 if (s->ralf >= 0) s->ralf++;
2127 if (s->blwf >= 0) s->blwf++;
2128 if (s->pref >= 0) s->pref++;
2129 s->base ++;
2135 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2137 if (s->blwf >= 0 && g->blwf > g->base)
2139 int j,loc;
2140 int g_offset;
2141 for (loc = s->end; loc > s->blwf; loc--)
2142 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2143 break;
2145 g_offset = (loc - s->blwf) - 1;
2147 if (loc != s->blwf)
2149 WORD blwf = glyphs[g->blwf];
2150 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2151 /* do not care about the pwChar array anymore, just the glyphs */
2152 for (j = 0; j < g_offset; j++)
2153 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2154 glyphs[g->blwf + g_offset] = blwf;
2159 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2161 int i;
2163 /* reorder previously moved Matras to correct position*/
2164 for (i = s->start; i < s->base; i++)
2166 if (lexical(pwChar[i]) == lex_Matra_pre)
2168 int j;
2169 int g_start = g->start + i - s->start;
2170 if (g_start < g->base -1 )
2172 WCHAR og = glyphs[g_start];
2173 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2174 for (j = g_start; j < g->base-1; j++)
2175 glyphs[j] = glyphs[j+1];
2176 glyphs[g->base-1] = og;
2182 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2184 if (s->pref >= 0 && g->pref > g->base)
2186 int j;
2187 WCHAR og = glyphs[g->pref];
2188 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2189 for (j = g->pref; j > g->base; j--)
2190 glyphs[j] = glyphs[j-1];
2191 glyphs[g->base] = og;
2195 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2197 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2198 if (s->start == s->base && s->base == s->end) return;
2199 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2201 Reorder_Ra_follows_base(pwChar, s, lexical);
2202 Reorder_Matra_precede_base(pwChar, s, lexical);
2205 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2207 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2208 if (s->start == s->base && s->base == s->end) return;
2209 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2211 Reorder_Ra_follows_matra(pwChar, s, lexical);
2212 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2215 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2217 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2218 if (s->start == s->base && s->base == s->end) return;
2219 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2221 Reorder_Ra_follows_base(pwChar, s, lexical);
2222 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2225 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2227 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2228 if (s->start == s->base && s->base == s->end) return;
2229 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2231 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2232 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2235 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2237 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2238 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2239 if (s->start == s->base && s->base == s->end) return;
2240 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2242 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2245 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2247 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2248 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2249 if (s->start == s->base && s->base == s->end) return;
2250 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2252 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2253 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2257 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2259 if (shift == 0)
2260 return;
2262 if (glyph_index->start > index)
2263 glyph_index->start += shift;
2264 if (glyph_index->base > index)
2265 glyph_index->base+= shift;
2266 if (glyph_index->end > index)
2267 glyph_index->end+= shift;
2268 if (glyph_index->ralf > index)
2269 glyph_index->ralf+= shift;
2270 if (glyph_index->blwf > index)
2271 glyph_index->blwf+= shift;
2272 if (glyph_index->pref > index)
2273 glyph_index->pref+= shift;
2276 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 )
2278 int index = glyph_index->start;
2280 if (!feature)
2281 return;
2283 while(index <= glyph_index->end)
2285 INT nextIndex;
2286 INT prevCount = *pcGlyphs;
2287 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2288 if (nextIndex > GSUB_E_NOGLYPH)
2290 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2291 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2292 index = nextIndex;
2294 else
2295 index++;
2299 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2301 int i = 0;
2302 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)))))
2303 i++;
2304 if (index + i <= end-1)
2305 return index + i;
2306 else
2307 return -1;
2310 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)
2312 INT index, nextIndex;
2313 INT count,g_offset;
2315 count = syllable->base - syllable->start;
2317 g_offset = 0;
2318 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2319 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2321 INT prevCount = *pcGlyphs;
2322 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2323 if (nextIndex > GSUB_E_NOGLYPH)
2325 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2326 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2327 g_offset += (*pcGlyphs - prevCount);
2330 index+=2;
2331 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2335 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)
2337 INT nextIndex;
2338 INT prevCount = *pcGlyphs;
2340 if (syllable->ralf >= 0)
2342 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2343 if (nextIndex > GSUB_E_NOGLYPH)
2345 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2346 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2351 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2353 int i = 0;
2354 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2355 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2356 is_consonant(lexical(pwChars[index+i+1])))))
2357 i++;
2358 if (index + i <= end-1)
2359 return index+i;
2360 else
2361 return -1;
2364 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)
2366 INT index, nextIndex;
2367 INT count, g_offset=0;
2368 INT ralf = syllable->ralf;
2370 count = syllable->end - syllable->base;
2372 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2374 while (index >= 0)
2376 INT prevCount = *pcGlyphs;
2377 if (ralf >=0 && ralf < index)
2379 g_offset--;
2380 ralf = -1;
2383 if (!modern)
2385 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2386 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2387 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2390 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2391 if (nextIndex > GSUB_E_NOGLYPH)
2393 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2394 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2395 g_offset += (*pcGlyphs - prevCount);
2397 else if (!modern)
2399 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2400 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2401 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2404 index+=2;
2405 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2409 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)
2411 int c;
2412 int overall_shift = 0;
2413 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2414 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2415 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2416 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2417 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2418 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2419 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2420 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2421 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2422 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2423 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2424 IndicSyllable glyph_indexs;
2426 for (c = 0; c < syllable_count; c++)
2428 int old_end;
2429 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2430 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2431 old_end = glyph_indexs.end;
2433 if (locl)
2435 TRACE("applying feature locl\n");
2436 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2438 if (nukt)
2440 TRACE("applying feature nukt\n");
2441 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2443 if (akhn)
2445 TRACE("applying feature akhn\n");
2446 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2449 if (rphf)
2450 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2451 if (rkrf)
2453 TRACE("applying feature rkrf\n");
2454 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2456 if (pref)
2457 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2458 if (blwf)
2460 if (!modern)
2461 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2463 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2466 if (half)
2467 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2468 if (pstf)
2470 TRACE("applying feature pstf\n");
2471 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2473 if (vatu)
2475 TRACE("applying feature vatu\n");
2476 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2478 if (cjct)
2480 TRACE("applying feature cjct\n");
2481 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2484 if (second_reorder)
2485 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2487 overall_shift += glyph_indexs.end - old_end;
2491 static inline int unicode_lex(WCHAR c)
2493 int type;
2495 if (!c) return lex_Generic;
2496 if (c == 0x200D) return lex_ZWJ;
2497 if (c == 0x200C) return lex_ZWNJ;
2498 if (c == 0x00A0) return lex_NBSP;
2500 type = get_table_entry( indic_syllabic_table, c );
2502 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2504 switch( type )
2506 case 0x0d07: /* Unknown */
2507 case 0x0e07: /* Unknwon */
2508 default: return lex_Generic;
2509 case 0x0001:
2510 case 0x0002:
2511 case 0x0011:
2512 case 0x0012:
2513 case 0x0013:
2514 case 0x0014: return lex_Modifier;
2515 case 0x0003:
2516 case 0x0009:
2517 case 0x000a:
2518 case 0x000b:
2519 case 0x000d:
2520 case 0x000e:
2521 case 0x000f:
2522 case 0x0010: return lex_Consonant;
2523 case 0x0004: return lex_Nukta;
2524 case 0x0005: return lex_Halant;
2525 case 0x0006:
2526 case 0x0008: return lex_Vowel;
2527 case 0x0007:
2528 case 0x0107: return lex_Matra_post;
2529 case 0x0207:
2530 case 0x0307: return lex_Matra_pre;
2531 case 0x0807:
2532 case 0x0907:
2533 case 0x0a07:
2534 case 0x0b07:
2535 case 0x0c07:
2536 case 0x0407: return lex_Composed_Vowel;
2537 case 0x0507: return lex_Matra_above;
2538 case 0x0607: return lex_Matra_below;
2539 case 0x000c: return lex_Ra;
2543 static int sinhala_lex(WCHAR c)
2545 switch (c)
2547 case 0x0DDA:
2548 case 0x0DDD:
2549 case 0x0DDC:
2550 case 0x0DDE: return lex_Matra_post;
2551 default:
2552 return unicode_lex(c);
2556 static const VowelComponents Sinhala_vowels[] = {
2557 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2558 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2559 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2560 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2561 {0x0000, {0x0000,0x0000,0x0}}};
2563 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2565 int cCount = cChars;
2566 int i;
2567 WCHAR *input;
2568 IndicSyllable *syllables = NULL;
2569 int syllable_count = 0;
2571 if (*pcGlyphs != cChars)
2573 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2574 return;
2577 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2579 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2581 /* Step 1: Decompose multi part vowels */
2582 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2584 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2586 /* Step 2: Reorder within Syllables */
2587 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2588 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2590 /* Step 3: Strip dangling joiners */
2591 for (i = 0; i < cCount; i++)
2593 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2594 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2595 input[i] = 0x0020;
2598 /* Step 4: Base Form application to syllables */
2599 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2600 *pcGlyphs = cCount;
2601 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2603 HeapFree(GetProcessHeap(),0,input);
2604 HeapFree(GetProcessHeap(),0,syllables);
2607 static int devanagari_lex(WCHAR c)
2609 switch (c)
2611 case 0x0930: return lex_Ra;
2612 default:
2613 return unicode_lex(c);
2617 static const ConsonantComponents Devanagari_consonants[] ={
2618 {{0x0928, 0x093C, 0x00000}, 0x0929},
2619 {{0x0930, 0x093C, 0x00000}, 0x0931},
2620 {{0x0933, 0x093C, 0x00000}, 0x0934},
2621 {{0x0915, 0x093C, 0x00000}, 0x0958},
2622 {{0x0916, 0x093C, 0x00000}, 0x0959},
2623 {{0x0917, 0x093C, 0x00000}, 0x095A},
2624 {{0x091C, 0x093C, 0x00000}, 0x095B},
2625 {{0x0921, 0x093C, 0x00000}, 0x095C},
2626 {{0x0922, 0x093C, 0x00000}, 0x095D},
2627 {{0x092B, 0x093C, 0x00000}, 0x095E},
2628 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2630 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2632 int cCount = cChars;
2633 WCHAR *input;
2634 IndicSyllable *syllables = NULL;
2635 int syllable_count = 0;
2636 BOOL modern = get_GSUB_Indic2(psa, psc);
2638 if (*pcGlyphs != cChars)
2640 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2641 return;
2644 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2645 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2647 /* Step 1: Compose Consonant and Nukta */
2648 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2649 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2651 /* Step 2: Reorder within Syllables */
2652 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2653 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2654 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2655 *pcGlyphs = cCount;
2657 /* Step 3: Base Form application to syllables */
2658 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2660 HeapFree(GetProcessHeap(),0,input);
2661 HeapFree(GetProcessHeap(),0,syllables);
2664 static int bengali_lex(WCHAR c)
2666 switch (c)
2668 case 0x09B0: return lex_Ra;
2669 default:
2670 return unicode_lex(c);
2674 static const VowelComponents Bengali_vowels[] = {
2675 {0x09CB, {0x09C7,0x09BE,0x0000}},
2676 {0x09CC, {0x09C7,0x09D7,0x0000}},
2677 {0x0000, {0x0000,0x0000,0x0000}}};
2679 static const ConsonantComponents Bengali_consonants[] = {
2680 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2681 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2682 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2683 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2684 {{0x0000,0x0000,0x0000}, 0x0000}};
2686 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2688 int cCount = cChars;
2689 WCHAR *input;
2690 IndicSyllable *syllables = NULL;
2691 int syllable_count = 0;
2692 BOOL modern = get_GSUB_Indic2(psa, psc);
2694 if (*pcGlyphs != cChars)
2696 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2697 return;
2700 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2701 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2703 /* Step 1: Decompose Vowels and Compose Consonents */
2704 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2705 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2706 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2708 /* Step 2: Reorder within Syllables */
2709 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2710 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2711 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2712 *pcGlyphs = cCount;
2714 /* Step 3: Initial form is only applied to the beginning of words */
2715 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2717 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2719 int index = cCount;
2720 int gCount = 1;
2721 if (index > 0) index++;
2723 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2727 /* Step 4: Base Form application to syllables */
2728 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2730 HeapFree(GetProcessHeap(),0,input);
2731 HeapFree(GetProcessHeap(),0,syllables);
2734 static int gurmukhi_lex(WCHAR c)
2736 if (c == 0x0A71)
2737 return lex_Modifier;
2738 else
2739 return unicode_lex(c);
2742 static const ConsonantComponents Gurmukhi_consonants[] = {
2743 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2744 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2745 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2746 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2747 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2748 {{0x0000,0x0000,0x0000}, 0x0000}};
2750 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2752 int cCount = cChars;
2753 WCHAR *input;
2754 IndicSyllable *syllables = NULL;
2755 int syllable_count = 0;
2756 BOOL modern = get_GSUB_Indic2(psa, psc);
2758 if (*pcGlyphs != cChars)
2760 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2761 return;
2764 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2765 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2767 /* Step 1: Compose Consonents */
2768 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2769 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2771 /* Step 2: Reorder within Syllables */
2772 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2773 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2774 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2775 *pcGlyphs = cCount;
2777 /* Step 3: Base Form application to syllables */
2778 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2780 HeapFree(GetProcessHeap(),0,input);
2781 HeapFree(GetProcessHeap(),0,syllables);
2784 static int gujarati_lex(WCHAR c)
2786 switch (c)
2788 case 0x0AB0: return lex_Ra;
2789 default:
2790 return unicode_lex(c);
2794 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2796 int cCount = cChars;
2797 WCHAR *input;
2798 IndicSyllable *syllables = NULL;
2799 int syllable_count = 0;
2800 BOOL modern = get_GSUB_Indic2(psa, psc);
2802 if (*pcGlyphs != cChars)
2804 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2805 return;
2808 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2809 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2811 /* Step 1: Reorder within Syllables */
2812 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2813 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2814 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2815 *pcGlyphs = cCount;
2817 /* Step 2: Base Form application to syllables */
2818 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2820 HeapFree(GetProcessHeap(),0,input);
2821 HeapFree(GetProcessHeap(),0,syllables);
2824 static int oriya_lex(WCHAR c)
2826 switch (c)
2828 case 0x0B30: return lex_Ra;
2829 default:
2830 return unicode_lex(c);
2834 static const VowelComponents Oriya_vowels[] = {
2835 {0x0B48, {0x0B47,0x0B56,0x0000}},
2836 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2837 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2838 {0x0000, {0x0000,0x0000,0x0000}}};
2840 static const ConsonantComponents Oriya_consonants[] = {
2841 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2842 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2843 {{0x0000,0x0000,0x0000}, 0x0000}};
2845 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2847 int cCount = cChars;
2848 WCHAR *input;
2849 IndicSyllable *syllables = NULL;
2850 int syllable_count = 0;
2851 BOOL modern = get_GSUB_Indic2(psa, psc);
2853 if (*pcGlyphs != cChars)
2855 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2856 return;
2859 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2860 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2862 /* Step 1: Decompose Vowels and Compose Consonents */
2863 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2864 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2865 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2867 /* Step 2: Reorder within Syllables */
2868 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2869 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2870 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2871 *pcGlyphs = cCount;
2873 /* Step 3: Base Form application to syllables */
2874 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2876 HeapFree(GetProcessHeap(),0,input);
2877 HeapFree(GetProcessHeap(),0,syllables);
2880 static int tamil_lex(WCHAR c)
2882 return unicode_lex(c);
2885 static const VowelComponents Tamil_vowels[] = {
2886 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2887 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2888 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2889 {0x0000, {0x0000,0x0000,0x0000}}};
2891 static const ConsonantComponents Tamil_consonants[] = {
2892 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2893 {{0x0000,0x0000,0x0000}, 0x0000}};
2895 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2897 int cCount = cChars;
2898 WCHAR *input;
2899 IndicSyllable *syllables = NULL;
2900 int syllable_count = 0;
2901 BOOL modern = get_GSUB_Indic2(psa, psc);
2903 if (*pcGlyphs != cChars)
2905 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2906 return;
2909 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2910 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2912 /* Step 1: Decompose Vowels and Compose Consonents */
2913 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2914 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2915 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2917 /* Step 2: Reorder within Syllables */
2918 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2919 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2920 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2921 *pcGlyphs = cCount;
2923 /* Step 3: Base Form application to syllables */
2924 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2926 HeapFree(GetProcessHeap(),0,input);
2927 HeapFree(GetProcessHeap(),0,syllables);
2930 static int telugu_lex(WCHAR c)
2932 switch (c)
2934 case 0x0C43:
2935 case 0x0C44: return lex_Modifier;
2936 default:
2937 return unicode_lex(c);
2941 static const VowelComponents Telugu_vowels[] = {
2942 {0x0C48, {0x0C46,0x0C56,0x0000}},
2943 {0x0000, {0x0000,0x0000,0x0000}}};
2945 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2947 int cCount = cChars;
2948 WCHAR *input;
2949 IndicSyllable *syllables = NULL;
2950 int syllable_count = 0;
2951 BOOL modern = get_GSUB_Indic2(psa, psc);
2953 if (*pcGlyphs != cChars)
2955 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2956 return;
2959 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2960 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2962 /* Step 1: Decompose Vowels */
2963 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2964 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2966 /* Step 2: Reorder within Syllables */
2967 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2968 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2969 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2970 *pcGlyphs = cCount;
2972 /* Step 3: Base Form application to syllables */
2973 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2975 HeapFree(GetProcessHeap(),0,input);
2976 HeapFree(GetProcessHeap(),0,syllables);
2979 static int kannada_lex(WCHAR c)
2981 switch (c)
2983 case 0x0CB0: return lex_Ra;
2984 default:
2985 return unicode_lex(c);
2989 static const VowelComponents Kannada_vowels[] = {
2990 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2991 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2992 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2993 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2994 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2995 {0x0000, {0x0000,0x0000,0x0000}}};
2997 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2999 int cCount = cChars;
3000 WCHAR *input;
3001 IndicSyllable *syllables = NULL;
3002 int syllable_count = 0;
3003 BOOL modern = get_GSUB_Indic2(psa, psc);
3005 if (*pcGlyphs != cChars)
3007 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3008 return;
3011 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
3012 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3014 /* Step 1: Decompose Vowels */
3015 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
3016 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
3018 /* Step 2: Reorder within Syllables */
3019 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
3020 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3021 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3022 *pcGlyphs = cCount;
3024 /* Step 3: Base Form application to syllables */
3025 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
3027 HeapFree(GetProcessHeap(),0,input);
3028 HeapFree(GetProcessHeap(),0,syllables);
3031 static int malayalam_lex(WCHAR c)
3033 return unicode_lex(c);
3036 static const VowelComponents Malayalam_vowels[] = {
3037 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
3038 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
3039 {0x0D4C, {0x0D46,0x0D57,0x0000}},
3040 {0x0000, {0x0000,0x0000,0x0000}}};
3042 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3044 int cCount = cChars;
3045 WCHAR *input;
3046 IndicSyllable *syllables = NULL;
3047 int syllable_count = 0;
3048 BOOL modern = get_GSUB_Indic2(psa, psc);
3050 if (*pcGlyphs != cChars)
3052 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3053 return;
3056 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
3057 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3059 /* Step 1: Decompose Vowels */
3060 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
3061 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
3063 /* Step 2: Reorder within Syllables */
3064 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
3065 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3066 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3067 *pcGlyphs = cCount;
3069 /* Step 3: Base Form application to syllables */
3070 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
3072 HeapFree(GetProcessHeap(),0,input);
3073 HeapFree(GetProcessHeap(),0,syllables);
3076 static int khmer_lex(WCHAR c)
3078 return unicode_lex(c);
3081 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3083 int cCount = cChars;
3084 WCHAR *input;
3085 IndicSyllable *syllables = NULL;
3086 int syllable_count = 0;
3088 if (*pcGlyphs != cChars)
3090 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3091 return;
3094 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
3095 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
3097 /* Step 1: Reorder within Syllables */
3098 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
3099 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
3100 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
3101 *pcGlyphs = cCount;
3103 /* Step 2: Base Form application to syllables */
3104 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
3106 HeapFree(GetProcessHeap(),0,input);
3107 HeapFree(GetProcessHeap(),0,syllables);
3110 static inline BOOL mongolian_wordbreak(WCHAR chr)
3112 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
3115 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3117 INT *context_shape;
3118 INT dirL;
3119 int i;
3121 if (*pcGlyphs != cChars)
3123 ERR("Number of Glyphs and Chars need to match at the beginning\n");
3124 return;
3127 if (!psa->fLogicalOrder && psa->fRTL)
3128 dirL = -1;
3129 else
3130 dirL = 1;
3132 if (!psc->GSUB_Table)
3133 psc->GSUB_Table = load_gsub_table(hdc);
3135 if (!psc->GSUB_Table)
3136 return;
3138 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
3140 for (i = 0; i < cChars; i++)
3142 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
3144 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
3145 context_shape[i] = Xn;
3146 else
3147 context_shape[i] = Xl;
3149 else
3151 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
3152 context_shape[i] = Xr;
3153 else
3154 context_shape[i] = Xm;
3158 /* Contextual Shaping */
3159 i = 0;
3160 while(i < *pcGlyphs)
3162 INT nextIndex;
3163 INT prevCount = *pcGlyphs;
3164 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
3165 if (nextIndex > GSUB_E_NOGLYPH)
3167 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
3168 i = nextIndex;
3170 else
3171 i++;
3174 HeapFree(GetProcessHeap(),0,context_shape);
3177 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)
3179 int i,k;
3181 for (i = 0; i < cGlyphs; i++)
3183 int char_index[20];
3184 int char_count = 0;
3186 for (k = 0; k < cChars; k++)
3188 if (pwLogClust[k] == i)
3190 char_index[char_count] = k;
3191 char_count++;
3195 if (char_count == 0)
3196 continue;
3198 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3200 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3201 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3203 else
3204 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3207 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3208 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3211 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 )
3213 int i,k;
3214 int initGlyph, finaGlyph;
3215 INT dirR, dirL;
3216 BYTE *spaces;
3218 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3219 memset(spaces,0,cGlyphs);
3221 if (!psa->fLogicalOrder && psa->fRTL)
3223 initGlyph = cGlyphs-1;
3224 finaGlyph = 0;
3225 dirR = 1;
3226 dirL = -1;
3228 else
3230 initGlyph = 0;
3231 finaGlyph = cGlyphs-1;
3232 dirR = -1;
3233 dirL = 1;
3236 for (i = 0; i < cGlyphs; i++)
3238 for (k = 0; k < cChars; k++)
3239 if (pwLogClust[k] == i)
3241 if (pwcChars[k] == 0x0020)
3242 spaces[i] = 1;
3246 for (i = 0; i < cGlyphs; i++)
3248 int char_index[20];
3249 int char_count = 0;
3250 BOOL isInit, isFinal;
3252 for (k = 0; k < cChars; k++)
3254 if (pwLogClust[k] == i)
3256 char_index[char_count] = k;
3257 char_count++;
3261 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3262 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3264 if (char_count == 0)
3265 continue;
3267 if (char_count == 1)
3269 if (pwcChars[char_index[0]] == 0x0020) /* space */
3271 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3272 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3274 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3275 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3276 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3278 if (!isInit && !isFinal)
3279 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3280 else if (isInit)
3281 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3282 else
3283 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3285 else if (!isInit)
3287 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3288 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3289 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3290 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3291 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3292 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3293 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3294 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3295 else
3296 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3298 else if (!isInit && !isFinal)
3299 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3300 else
3301 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3303 else if (char_count == 2)
3305 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3306 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3307 else if (!isInit)
3308 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3309 else
3310 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3312 else if (!isInit && !isFinal)
3313 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3314 else
3315 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3318 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3319 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3320 HeapFree(GetProcessHeap(),0,spaces);
3323 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 )
3325 int i,k;
3326 int finaGlyph;
3327 INT dirL;
3328 BYTE *spaces;
3330 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3331 memset(spaces,0,cGlyphs);
3333 if (!psa->fLogicalOrder && psa->fRTL)
3335 finaGlyph = 0;
3336 dirL = -1;
3338 else
3340 finaGlyph = cGlyphs-1;
3341 dirL = 1;
3344 for (i = 0; i < cGlyphs; i++)
3346 for (k = 0; k < cChars; k++)
3347 if (pwLogClust[k] == i)
3349 if (pwcChars[k] == 0x0020)
3350 spaces[i] = 1;
3354 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3356 for (i = 0; i < cGlyphs; i++)
3358 int char_index[20];
3359 int char_count = 0;
3361 for (k = 0; k < cChars; k++)
3363 if (pwLogClust[k] == i)
3365 char_index[char_count] = k;
3366 char_count++;
3370 if (char_count == 0)
3371 continue;
3373 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3375 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3376 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3378 else if (i == finaGlyph)
3379 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3380 else
3381 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3383 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3384 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3385 pGlyphProp[i].sva.fClusterStart = 0;
3388 HeapFree(GetProcessHeap(),0,spaces);
3389 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3391 /* Do not allow justification between marks and their base */
3392 for (i = 0; i < cGlyphs; i++)
3394 if (!pGlyphProp[i].sva.fClusterStart)
3395 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3399 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)
3401 int i,k;
3403 for (i = 0; i < cGlyphs; i++)
3405 int char_index[20];
3406 int char_count = 0;
3408 for (k = 0; k < cChars; k++)
3410 if (pwLogClust[k] == i)
3412 char_index[char_count] = k;
3413 char_count++;
3417 if (char_count == 0)
3418 continue;
3420 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3422 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3423 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3425 else
3426 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3428 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3429 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3432 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)
3434 int i,k;
3436 for (i = 0; i < cGlyphs; i++)
3438 int char_index[20];
3439 int char_count = 0;
3441 for (k = 0; k < cChars; k++)
3443 if (pwLogClust[k] == i)
3445 char_index[char_count] = k;
3446 char_count++;
3450 if (char_count == 0)
3451 continue;
3453 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3455 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3456 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3458 else
3459 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3461 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3462 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3464 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3465 for (i = 0; i < cGlyphs; i++)
3467 if (!pGlyphProp[i].sva.fClusterStart)
3469 pGlyphProp[i].sva.fDiacritic = 0;
3470 pGlyphProp[i].sva.fZeroWidth = 0;
3475 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)
3477 int i,k;
3479 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3480 for (i = 0; i < cGlyphs; i++)
3482 int char_index[20];
3483 int char_count = 0;
3485 for (k = 0; k < cChars; k++)
3487 if (pwLogClust[k] == i)
3489 char_index[char_count] = k;
3490 char_count++;
3494 if (override_gsub)
3496 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3497 pGlyphProp[i].sva.fDiacritic = FALSE;
3498 pGlyphProp[i].sva.fZeroWidth = FALSE;
3501 if (char_count == 0)
3502 continue;
3504 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3506 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3507 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3509 else
3510 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3512 pGlyphProp[i].sva.fClusterStart = 0;
3513 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3514 switch (lexical(pwcChars[char_index[k]]))
3516 case lex_Matra_pre:
3517 case lex_Matra_post:
3518 case lex_Matra_above:
3519 case lex_Matra_below:
3520 case lex_Modifier:
3521 case lex_Halant:
3522 break;
3523 case lex_ZWJ:
3524 case lex_ZWNJ:
3525 /* check for dangling joiners */
3526 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3527 pGlyphProp[i].sva.fClusterStart = 1;
3528 else
3529 k = char_count;
3530 break;
3531 default:
3532 pGlyphProp[i].sva.fClusterStart = 1;
3533 break;
3537 if (use_syllables)
3539 IndicSyllable *syllables = NULL;
3540 int syllable_count = 0;
3541 BOOL modern = get_GSUB_Indic2(psa, psc);
3543 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3545 for (i = 0; i < syllable_count; i++)
3547 int j;
3548 WORD g = pwLogClust[syllables[i].start];
3549 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3551 if (pwLogClust[j] != g)
3553 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3554 pwLogClust[j] = g;
3559 HeapFree(GetProcessHeap(), 0, syllables);
3562 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3565 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 )
3567 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3570 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 )
3572 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3575 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 )
3577 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3580 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 )
3582 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3585 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 )
3587 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3590 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 )
3592 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3595 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 )
3597 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3600 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 )
3602 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3605 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 )
3607 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3610 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 )
3612 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3615 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 )
3617 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3620 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)
3622 if (ShapingData[psa->eScript].charGlyphPropProc)
3623 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3624 else
3625 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3628 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3630 if (!psc->GSUB_Table)
3631 psc->GSUB_Table = load_gsub_table(hdc);
3633 if (ShapingData[psa->eScript].contextProc)
3634 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3637 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)
3639 int i;
3640 INT dirL;
3642 if (!rpRangeProperties)
3643 return;
3645 if (!psc->GSUB_Table)
3646 psc->GSUB_Table = load_gsub_table(hdc);
3648 if (!psc->GSUB_Table)
3649 return;
3651 if (!psa->fLogicalOrder && psa->fRTL)
3652 dirL = -1;
3653 else
3654 dirL = 1;
3656 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3658 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3659 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3663 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3665 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3666 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3668 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3671 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3673 const GSUB_Feature *feature;
3674 int i;
3676 if (!ShapingData[psa->eScript].requiredFeatures)
3677 return S_OK;
3679 if (!psc->GSUB_Table)
3680 psc->GSUB_Table = load_gsub_table(hdc);
3682 /* we need to have at least one of the required features */
3683 i = 0;
3684 while (ShapingData[psa->eScript].requiredFeatures[i])
3686 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3687 if (feature)
3688 return S_OK;
3689 i++;
3692 return USP_E_SCRIPT_NOT_IN_FONT;
3695 static VOID *load_CMAP_format12_table(HDC hdc, ScriptCache *psc)
3697 CMAP_Header *CMAP_Table = NULL;
3698 int length;
3699 int i;
3701 if (!psc->CMAP_Table)
3703 length = GetFontData(hdc, CMAP_TAG , 0, NULL, 0);
3704 if (length != GDI_ERROR)
3706 psc->CMAP_Table = HeapAlloc(GetProcessHeap(),0,length);
3707 GetFontData(hdc, CMAP_TAG , 0, psc->CMAP_Table, length);
3708 TRACE("Loaded cmap table of %i bytes\n",length);
3710 else
3711 return NULL;
3714 CMAP_Table = psc->CMAP_Table;
3716 for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
3718 if ( (GET_BE_WORD(CMAP_Table->tables[i].platformID) == 3) &&
3719 (GET_BE_WORD(CMAP_Table->tables[i].encodingID) == 10) )
3721 CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
3722 if (GET_BE_WORD(format->format) == 12)
3723 return format;
3726 return NULL;
3729 static int compare_group(const void *a, const void* b)
3731 const DWORD *chr = a;
3732 const CMAP_SegmentedCoverage_group *group = b;
3734 if (*chr < GET_BE_DWORD(group->startCharCode))
3735 return -1;
3736 if (*chr > GET_BE_DWORD(group->endCharCode))
3737 return 1;
3738 return 0;
3741 DWORD CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags)
3743 /* BMP: use gdi32 for ease */
3744 if (utf32c < 0x10000)
3746 WCHAR ch = utf32c;
3747 return GetGlyphIndicesW(hdc,&ch, 1, pgi, flags);
3750 if (!psc->CMAP_format12_Table)
3751 psc->CMAP_format12_Table = load_CMAP_format12_table(hdc, psc);
3753 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
3754 *pgi = 0xffff;
3755 else
3756 *pgi = 0;
3758 if (psc->CMAP_format12_Table)
3760 CMAP_SegmentedCoverage *format = NULL;
3761 CMAP_SegmentedCoverage_group *group = NULL;
3763 format = (CMAP_SegmentedCoverage *)psc->CMAP_format12_Table;
3765 group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
3766 sizeof(CMAP_SegmentedCoverage_group), compare_group);
3768 if (group)
3770 DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
3771 *pgi = GET_BE_DWORD(group->startGlyphID) + offset;
3772 return 0;
3775 return 0;