[WLAN-BRINGUP]
[reactos.git] / dll / win32 / usp10 / shape.c
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
3 *
4 * Copyright 2010 CodeWeavers, Aric Stewart
5 *
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.
10 *
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.
15 *
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
19 *
20 */
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "usp10.h"
29 #include "winternl.h"
30
31 #include "usp10_internal.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
36
37 #define FIRST_ARABIC_CHAR 0x0600
38 #define LAST_ARABIC_CHAR 0x06ff
39
40 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
41 WCHAR*, INT, WORD*, INT*, INT, WORD*);
42
43 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56
57 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
58
59 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
60 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
61 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
62 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
63 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
64 static void ShapeCharGlyphProp_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 );
65 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 );
66 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 );
67 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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74
75 extern const unsigned short indic_syllabic_table[];
76 extern const unsigned short wine_shaping_table[];
77 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
78
79 enum joining_types {
80 jtU,
81 jtT,
82 jtR,
83 jtL,
84 jtD,
85 jtC
86 };
87
88 enum joined_forms {
89 Xn=0,
90 Xr,
91 Xl,
92 Xm,
93 /* Syriac Alaph */
94 Afj,
95 Afn,
96 Afx
97 };
98
99 #ifdef WORDS_BIGENDIAN
100 #define GET_BE_WORD(x) (x)
101 #else
102 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
103 #endif
104
105 /* These are all structures needed for the GSUB table */
106 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
107 #define GSUB_E_NOFEATURE -2
108 #define GSUB_E_NOGLYPH -1
109
110 typedef struct {
111 DWORD version;
112 WORD ScriptList;
113 WORD FeatureList;
114 WORD LookupList;
115 } GSUB_Header;
116
117 typedef struct {
118 CHAR ScriptTag[4];
119 WORD Script;
120 } GSUB_ScriptRecord;
121
122 typedef struct {
123 WORD ScriptCount;
124 GSUB_ScriptRecord ScriptRecord[1];
125 } GSUB_ScriptList;
126
127 typedef struct {
128 CHAR LangSysTag[4];
129 WORD LangSys;
130 } GSUB_LangSysRecord;
131
132 typedef struct {
133 WORD DefaultLangSys;
134 WORD LangSysCount;
135 GSUB_LangSysRecord LangSysRecord[1];
136 } GSUB_Script;
137
138 typedef struct {
139 WORD LookupOrder; /* Reserved */
140 WORD ReqFeatureIndex;
141 WORD FeatureCount;
142 WORD FeatureIndex[1];
143 } GSUB_LangSys;
144
145 typedef struct {
146 CHAR FeatureTag[4];
147 WORD Feature;
148 } GSUB_FeatureRecord;
149
150 typedef struct {
151 WORD FeatureCount;
152 GSUB_FeatureRecord FeatureRecord[1];
153 } GSUB_FeatureList;
154
155 typedef struct {
156 WORD FeatureParams; /* Reserved */
157 WORD LookupCount;
158 WORD LookupListIndex[1];
159 } GSUB_Feature;
160
161 typedef struct {
162 WORD LookupCount;
163 WORD Lookup[1];
164 } GSUB_LookupList;
165
166 typedef struct {
167 WORD LookupType;
168 WORD LookupFlag;
169 WORD SubTableCount;
170 WORD SubTable[1];
171 } GSUB_LookupTable;
172
173 typedef struct {
174 WORD CoverageFormat;
175 WORD GlyphCount;
176 WORD GlyphArray[1];
177 } GSUB_CoverageFormat1;
178
179 typedef struct {
180 WORD Start;
181 WORD End;
182 WORD StartCoverageIndex;
183 } GSUB_RangeRecord;
184
185 typedef struct {
186 WORD CoverageFormat;
187 WORD RangeCount;
188 GSUB_RangeRecord RangeRecord[1];
189 } GSUB_CoverageFormat2;
190
191 typedef struct {
192 WORD SubstFormat; /* = 1 */
193 WORD Coverage;
194 WORD DeltaGlyphID;
195 } GSUB_SingleSubstFormat1;
196
197 typedef struct {
198 WORD SubstFormat; /* = 2 */
199 WORD Coverage;
200 WORD GlyphCount;
201 WORD Substitute[1];
202 }GSUB_SingleSubstFormat2;
203
204 typedef struct {
205 WORD SubstFormat; /* = 1 */
206 WORD Coverage;
207 WORD SequenceCount;
208 WORD Sequence[1];
209 }GSUB_MultipleSubstFormat1;
210
211 typedef struct {
212 WORD GlyphCount;
213 WORD Substitute[1];
214 }GSUB_Sequence;
215
216 typedef struct {
217 WORD SubstFormat; /* = 1 */
218 WORD Coverage;
219 WORD LigSetCount;
220 WORD LigatureSet[1];
221 }GSUB_LigatureSubstFormat1;
222
223 typedef struct {
224 WORD LigatureCount;
225 WORD Ligature[1];
226 }GSUB_LigatureSet;
227
228 typedef struct{
229 WORD LigGlyph;
230 WORD CompCount;
231 WORD Component[1];
232 }GSUB_Ligature;
233
234 typedef struct{
235 WORD SequenceIndex;
236 WORD LookupListIndex;
237
238 }GSUB_SubstLookupRecord;
239
240 typedef struct{
241 WORD SubstFormat; /* = 1 */
242 WORD Coverage;
243 WORD ChainSubRuleSetCount;
244 WORD ChainSubRuleSet[1];
245 }GSUB_ChainContextSubstFormat1;
246
247 typedef struct {
248 WORD SubstFormat; /* = 3 */
249 WORD BacktrackGlyphCount;
250 WORD Coverage[1];
251 }GSUB_ChainContextSubstFormat3_1;
252
253 typedef struct{
254 WORD InputGlyphCount;
255 WORD Coverage[1];
256 }GSUB_ChainContextSubstFormat3_2;
257
258 typedef struct{
259 WORD LookaheadGlyphCount;
260 WORD Coverage[1];
261 }GSUB_ChainContextSubstFormat3_3;
262
263 typedef struct{
264 WORD SubstCount;
265 GSUB_SubstLookupRecord SubstLookupRecord[1];
266 }GSUB_ChainContextSubstFormat3_4;
267
268 typedef struct {
269 WORD SubstFormat; /* = 1 */
270 WORD Coverage;
271 WORD AlternateSetCount;
272 WORD AlternateSet[1];
273 } GSUB_AlternateSubstFormat1;
274
275 typedef struct{
276 WORD GlyphCount;
277 WORD Alternate[1];
278 } GSUB_AlternateSet;
279
280 /* These are all structures needed for the GDEF table */
281 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
282
283 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
284
285 typedef struct {
286 DWORD Version;
287 WORD GlyphClassDef;
288 WORD AttachList;
289 WORD LigCaretList;
290 WORD MarkAttachClassDef;
291 } GDEF_Header;
292
293 typedef struct {
294 WORD ClassFormat;
295 WORD StartGlyph;
296 WORD GlyphCount;
297 WORD ClassValueArray[1];
298 } GDEF_ClassDefFormat1;
299
300 typedef struct {
301 WORD Start;
302 WORD End;
303 WORD Class;
304 } GDEF_ClassRangeRecord;
305
306 typedef struct {
307 WORD ClassFormat;
308 WORD ClassRangeCount;
309 GDEF_ClassRangeRecord ClassRangeRecord[1];
310 } GDEF_ClassDefFormat2;
311
312 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
313
314 typedef struct tagVowelComponents
315 {
316 WCHAR base;
317 WCHAR parts[3];
318 } VowelComponents;
319
320 typedef struct tagConsonantComponents
321 {
322 WCHAR parts[3];
323 WCHAR output;
324 } ConsonantComponents;
325
326 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
327
328 /* the orders of joined_forms and contextual_features need to line up */
329 static const char* contextual_features[] =
330 {
331 "isol",
332 "fina",
333 "init",
334 "medi",
335 /* Syriac Alaph */
336 "med2",
337 "fin2",
338 "fin3"
339 };
340
341 static OPENTYPE_FEATURE_RECORD standard_features[] =
342 {
343 { MS_MAKE_TAG('c','c','m','p'), 1},
344 { MS_MAKE_TAG('l','o','c','l'), 1},
345 };
346
347 static OPENTYPE_FEATURE_RECORD latin_features[] =
348 {
349 { MS_MAKE_TAG('l','i','g','a'), 1},
350 { MS_MAKE_TAG('c','l','i','g'), 1},
351 };
352
353 static OPENTYPE_FEATURE_RECORD arabic_features[] =
354 {
355 { MS_MAKE_TAG('r','l','i','g'), 1},
356 { MS_MAKE_TAG('c','a','l','t'), 1},
357 { MS_MAKE_TAG('l','i','g','a'), 1},
358 { MS_MAKE_TAG('d','l','i','g'), 1},
359 { MS_MAKE_TAG('c','s','w','h'), 1},
360 { MS_MAKE_TAG('m','s','e','t'), 1},
361 };
362
363 static const char* required_arabic_features[] =
364 {
365 "fina",
366 "init",
367 "medi",
368 "rlig",
369 NULL
370 };
371
372 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
373 {
374 { MS_MAKE_TAG('d','l','i','g'), 0},
375 };
376
377 static OPENTYPE_FEATURE_RECORD syriac_features[] =
378 {
379 { MS_MAKE_TAG('r','l','i','g'), 1},
380 { MS_MAKE_TAG('c','a','l','t'), 1},
381 { MS_MAKE_TAG('l','i','g','a'), 1},
382 { MS_MAKE_TAG('d','l','i','g'), 1},
383 };
384
385 static const char* required_syriac_features[] =
386 {
387 "fina",
388 "fin2",
389 "fin3",
390 "init",
391 "medi",
392 "med2",
393 "rlig",
394 NULL
395 };
396
397 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
398 {
399 /* Presentation forms */
400 { MS_MAKE_TAG('b','l','w','s'), 1},
401 { MS_MAKE_TAG('a','b','v','s'), 1},
402 { MS_MAKE_TAG('p','s','t','s'), 1},
403 };
404
405 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
406 {
407 { MS_MAKE_TAG('a','b','v','s'), 1},
408 { MS_MAKE_TAG('b','l','w','s'), 1},
409 };
410
411 static OPENTYPE_FEATURE_RECORD phags_features[] =
412 {
413 { MS_MAKE_TAG('a','b','v','s'), 1},
414 { MS_MAKE_TAG('b','l','w','s'), 1},
415 { MS_MAKE_TAG('c','a','l','t'), 1},
416 };
417
418 static OPENTYPE_FEATURE_RECORD thai_features[] =
419 {
420 { MS_MAKE_TAG('c','c','m','p'), 1},
421 };
422
423 static const char* required_lao_features[] =
424 {
425 "ccmp",
426 NULL
427 };
428
429 static const char* required_devanagari_features[] =
430 {
431 "nukt",
432 "akhn",
433 "rphf",
434 "blwf",
435 "half",
436 "vatu",
437 "pres",
438 "abvs",
439 "blws",
440 "psts",
441 "haln",
442 NULL
443 };
444
445 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
446 {
447 { MS_MAKE_TAG('p','r','e','s'), 1},
448 { MS_MAKE_TAG('a','b','v','s'), 1},
449 { MS_MAKE_TAG('b','l','w','s'), 1},
450 { MS_MAKE_TAG('p','s','t','s'), 1},
451 { MS_MAKE_TAG('h','a','l','n'), 1},
452 { MS_MAKE_TAG('c','a','l','t'), 1},
453 };
454
455 static const char* required_bengali_features[] =
456 {
457 "nukt",
458 "akhn",
459 "rphf",
460 "blwf",
461 "half",
462 "vatu",
463 "pstf",
464 "init",
465 "abvs",
466 "blws",
467 "psts",
468 "haln",
469 NULL
470 };
471
472 static const char* required_gurmukhi_features[] =
473 {
474 "nukt",
475 "akhn",
476 "rphf",
477 "blwf",
478 "half",
479 "pstf",
480 "vatu",
481 "cjct",
482 "pres",
483 "abvs",
484 "blws",
485 "psts",
486 "haln",
487 "calt",
488 NULL
489 };
490
491 static const char* required_oriya_features[] =
492 {
493 "nukt",
494 "akhn",
495 "rphf",
496 "blwf",
497 "pstf",
498 "cjct",
499 "pres",
500 "abvs",
501 "blws",
502 "psts",
503 "haln",
504 "calt",
505 NULL
506 };
507
508 static const char* required_tamil_features[] =
509 {
510 "nukt",
511 "akhn",
512 "rphf",
513 "pref",
514 "half",
515 "pres",
516 "abvs",
517 "blws",
518 "psts",
519 "haln",
520 "calt",
521 NULL
522 };
523
524 static const char* required_telugu_features[] =
525 {
526 "nukt",
527 "akhn",
528 "rphf",
529 "pref",
530 "half",
531 "pstf",
532 "cjct",
533 "pres",
534 "abvs",
535 "blws",
536 "psts",
537 "haln",
538 "calt",
539 NULL
540 };
541
542 typedef struct ScriptShapeDataTag {
543 TEXTRANGE_PROPERTIES defaultTextRange;
544 const char** requiredFeatures;
545 CHAR otTag[5];
546 CHAR newOtTag[5];
547 ContextualShapingProc contextProc;
548 ShapeCharGlyphPropProc charGlyphPropProc;
549 } ScriptShapeData;
550
551 /* in order of scripts */
552 static const ScriptShapeData ShapingData[] =
553 {
554 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
555 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
556 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
557 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
558 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
559 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
560 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
561 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
562 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
563 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
564 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
565 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
566 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
567 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
568 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
569 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
570 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
571 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
572 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
573 {{ phags_features, 3}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
574 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
575 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
576 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
577 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
578 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
579 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
580 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
581 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
582 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
583 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
584 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
585 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
586 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
587 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
588 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
589 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
590 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
591 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
592 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
593 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
594 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
595 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
596 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
597 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
598 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
599 {{ latin_features, 2}, NULL, "latn" , "", NULL, NULL},
600 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
601 };
602
603 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
604 {
605 const GSUB_CoverageFormat1* cf1;
606
607 cf1 = table;
608
609 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
610 {
611 int count = GET_BE_WORD(cf1->GlyphCount);
612 int i;
613 TRACE("Coverage Format 1, %i glyphs\n",count);
614 for (i = 0; i < count; i++)
615 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
616 return i;
617 return -1;
618 }
619 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
620 {
621 const GSUB_CoverageFormat2* cf2;
622 int i;
623 int count;
624 cf2 = (const GSUB_CoverageFormat2*)cf1;
625
626 count = GET_BE_WORD(cf2->RangeCount);
627 TRACE("Coverage Format 2, %i ranges\n",count);
628 for (i = 0; i < count; i++)
629 {
630 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
631 return -1;
632 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
633 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
634 {
635 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
636 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
637 }
638 }
639 return -1;
640 }
641 else
642 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
643
644 return -1;
645 }
646
647 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
648 {
649 const GSUB_ScriptList *script;
650 const GSUB_Script *deflt = NULL;
651 int i;
652 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
653
654 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
655 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
656 {
657 const GSUB_Script *scr;
658 int offset;
659
660 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
661 scr = (const GSUB_Script*)((const BYTE*)script + offset);
662
663 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
664 return scr;
665 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
666 deflt = scr;
667 }
668 return deflt;
669 }
670
671 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
672 {
673 int i;
674 int offset;
675 const GSUB_LangSys *Lang;
676
677 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
678
679 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
680 {
681 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
682 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
683
684 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
685 return Lang;
686 }
687 offset = GET_BE_WORD(script->DefaultLangSys);
688 if (offset)
689 {
690 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
691 return Lang;
692 }
693 return NULL;
694 }
695
696 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
697 {
698 int i;
699 const GSUB_FeatureList *feature;
700 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
701
702 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
703 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
704 {
705 int index = GET_BE_WORD(lang->FeatureIndex[i]);
706 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
707 {
708 const GSUB_Feature *feat;
709 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
710 return feat;
711 }
712 }
713 return NULL;
714 }
715
716 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
717 {
718 int j;
719 TRACE("Single Substitution Subtable\n");
720
721 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
722 {
723 int offset;
724 const GSUB_SingleSubstFormat1 *ssf1;
725 offset = GET_BE_WORD(look->SubTable[j]);
726 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
727 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
728 {
729 int offset = GET_BE_WORD(ssf1->Coverage);
730 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
731 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
732 {
733 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
734 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
735 TRACE(" 0x%x\n",glyphs[glyph_index]);
736 return glyph_index + write_dir;
737 }
738 }
739 else
740 {
741 const GSUB_SingleSubstFormat2 *ssf2;
742 INT index;
743 INT offset;
744
745 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
746 offset = GET_BE_WORD(ssf1->Coverage);
747 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
748 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
749 TRACE(" Coverage index %i\n",index);
750 if (index != -1)
751 {
752 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
753 return GSUB_E_NOGLYPH;
754
755 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
756 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
757 TRACE("0x%x\n",glyphs[glyph_index]);
758 return glyph_index + write_dir;
759 }
760 }
761 }
762 return GSUB_E_NOGLYPH;
763 }
764
765 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
766 {
767 int j;
768 TRACE("Multiple Substitution Subtable\n");
769
770 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
771 {
772 int offset, index;
773 const GSUB_MultipleSubstFormat1 *msf1;
774 offset = GET_BE_WORD(look->SubTable[j]);
775 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
776
777 offset = GET_BE_WORD(msf1->Coverage);
778 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
779 if (index != -1)
780 {
781 const GSUB_Sequence *seq;
782 int sub_count;
783 int j;
784 offset = GET_BE_WORD(msf1->Sequence[index]);
785 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
786 sub_count = GET_BE_WORD(seq->GlyphCount);
787 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
788
789 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
790 glyphs[j] =glyphs[j-(sub_count-1)];
791
792 for (j = 0; j < sub_count; j++)
793 if (write_dir < 0)
794 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
795 else
796 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
797
798 *glyph_count = *glyph_count + (sub_count - 1);
799
800 if (TRACE_ON(uniscribe))
801 {
802 for (j = 0; j < sub_count; j++)
803 TRACE(" 0x%x",glyphs[glyph_index+j]);
804 TRACE("\n");
805 }
806
807 return glyph_index + (sub_count * write_dir);
808 }
809 }
810 return GSUB_E_NOGLYPH;
811 }
812
813 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
814 {
815 int j;
816 TRACE("Alternate Substitution Subtable\n");
817
818 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
819 {
820 int offset;
821 const GSUB_AlternateSubstFormat1 *asf1;
822 INT index;
823
824 offset = GET_BE_WORD(look->SubTable[j]);
825 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
826 offset = GET_BE_WORD(asf1->Coverage);
827
828 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
829 if (index != -1)
830 {
831 const GSUB_AlternateSet *as;
832 offset = GET_BE_WORD(asf1->AlternateSet[index]);
833 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
834 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
835 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
836 return GSUB_E_NOGLYPH;
837
838 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
839 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
840 TRACE(" 0x%x\n",glyphs[glyph_index]);
841 return glyph_index + write_dir;
842 }
843 }
844 return GSUB_E_NOGLYPH;
845 }
846
847 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
848 {
849 int j;
850
851 TRACE("Ligature Substitution Subtable\n");
852 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
853 {
854 const GSUB_LigatureSubstFormat1 *lsf1;
855 int offset,index;
856
857 offset = GET_BE_WORD(look->SubTable[j]);
858 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
859 offset = GET_BE_WORD(lsf1->Coverage);
860 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
861 TRACE(" Coverage index %i\n",index);
862 if (index != -1)
863 {
864 const GSUB_LigatureSet *ls;
865 int k, count;
866
867 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
868 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
869 count = GET_BE_WORD(ls->LigatureCount);
870 TRACE(" LigatureSet has %i members\n",count);
871 for (k = 0; k < count; k++)
872 {
873 const GSUB_Ligature *lig;
874 int CompCount,l,CompIndex;
875
876 offset = GET_BE_WORD(ls->Ligature[k]);
877 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
878 CompCount = GET_BE_WORD(lig->CompCount) - 1;
879 CompIndex = glyph_index+write_dir;
880 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
881 {
882 int CompGlyph;
883 CompGlyph = GET_BE_WORD(lig->Component[l]);
884 if (CompGlyph != glyphs[CompIndex])
885 break;
886 CompIndex += write_dir;
887 }
888 if (l == CompCount)
889 {
890 int replaceIdx = glyph_index;
891 if (write_dir < 0)
892 replaceIdx = glyph_index - CompCount;
893
894 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
895 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
896 TRACE("0x%x\n",glyphs[replaceIdx]);
897 if (CompCount > 0)
898 {
899 int j;
900 for (j = replaceIdx + 1; j < *glyph_count; j++)
901 glyphs[j] =glyphs[j+CompCount];
902 *glyph_count = *glyph_count - CompCount;
903 }
904 return replaceIdx + write_dir;
905 }
906 }
907 }
908 }
909 return GSUB_E_NOGLYPH;
910 }
911
912 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
913 {
914 int j;
915 BOOL done = FALSE;
916
917 TRACE("Chaining Contextual Substitution Subtable\n");
918 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
919 {
920 const GSUB_ChainContextSubstFormat1 *ccsf1;
921 int offset;
922 int dirLookahead = write_dir;
923 int dirBacktrack = -1 * write_dir;
924
925 offset = GET_BE_WORD(look->SubTable[j]);
926 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
927 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
928 {
929 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
930 continue;
931 }
932 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
933 {
934 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
935 continue;
936 }
937 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
938 {
939 int k;
940 int indexGlyphs;
941 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
942 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
943 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
944 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
945 int newIndex = glyph_index;
946
947 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
948
949 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
950
951 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
952 {
953 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
954 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
955 break;
956 }
957 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
958 continue;
959 TRACE("Matched Backtrack\n");
960
961 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
962
963 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
964 for (k = 0; k < indexGlyphs; k++)
965 {
966 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
967 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
968 break;
969 }
970 if (k != indexGlyphs)
971 continue;
972 TRACE("Matched IndexGlyphs\n");
973
974 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
975
976 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
977 {
978 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
979 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
980 break;
981 }
982 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
983 continue;
984 TRACE("Matched LookAhead\n");
985
986 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
987
988 if (GET_BE_WORD(ccsf3_4->SubstCount))
989 {
990 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
991 {
992 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
993 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
994
995 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
996 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
997 if (newIndex == -1)
998 {
999 ERR("Chain failed to generate a glyph\n");
1000 continue;
1001 }
1002 }
1003 return newIndex;
1004 }
1005 else return GSUB_E_NOGLYPH;
1006 }
1007 }
1008 return -1;
1009 }
1010
1011 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1012 {
1013 int offset;
1014 const GSUB_LookupTable *look;
1015
1016 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1017 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1018 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1019 switch(GET_BE_WORD(look->LookupType))
1020 {
1021 case 1:
1022 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1023 case 2:
1024 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1025 case 3:
1026 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1027 case 4:
1028 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1029 case 6:
1030 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1031 default:
1032 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1033 }
1034 return GSUB_E_NOGLYPH;
1035 }
1036
1037 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)
1038 {
1039 int i;
1040 int out_index = GSUB_E_NOGLYPH;
1041 const GSUB_LookupList *lookup;
1042
1043 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1044
1045 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1046 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1047 {
1048 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1049 if (out_index != GSUB_E_NOGLYPH)
1050 break;
1051 }
1052 if (out_index == GSUB_E_NOGLYPH)
1053 TRACE("lookups found no glyphs\n");
1054 else
1055 {
1056 int out2;
1057 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1058 if (out2!=GSUB_E_NOGLYPH)
1059 out_index = out2;
1060 }
1061 return out_index;
1062 }
1063
1064 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1065 {
1066 UINT charset;
1067
1068 if (psc->userScript != 0)
1069 {
1070 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1071 return ShapingData[psa->eScript].newOtTag;
1072 else
1073 return (char*)&psc->userScript;
1074 }
1075
1076 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1077 return ShapingData[psa->eScript].newOtTag;
1078
1079 if (ShapingData[psa->eScript].otTag[0] != 0)
1080 return ShapingData[psa->eScript].otTag;
1081
1082 /*
1083 * fall back to the font charset
1084 */
1085 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1086 switch (charset)
1087 {
1088 case ANSI_CHARSET: return "latn";
1089 case BALTIC_CHARSET: return "latn"; /* ?? */
1090 case CHINESEBIG5_CHARSET: return "hani";
1091 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1092 case GB2312_CHARSET: return "hani";
1093 case GREEK_CHARSET: return "grek";
1094 case HANGUL_CHARSET: return "hang";
1095 case RUSSIAN_CHARSET: return "cyrl";
1096 case SHIFTJIS_CHARSET: return "kana";
1097 case TURKISH_CHARSET: return "latn"; /* ?? */
1098 case VIETNAMESE_CHARSET: return "latn";
1099 case JOHAB_CHARSET: return "latn"; /* ?? */
1100 case ARABIC_CHARSET: return "arab";
1101 case HEBREW_CHARSET: return "hebr";
1102 case THAI_CHARSET: return "thai";
1103 default: return "latn";
1104 }
1105 }
1106
1107 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1108 {
1109 const GSUB_Feature *feature;
1110 const char* script;
1111 int i;
1112
1113 script = get_opentype_script(hdc,psa,psc,FALSE);
1114
1115 for (i = 0; i < psc->feature_count; i++)
1116 {
1117 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1118 return psc->features[i].feature;
1119 }
1120
1121 feature = NULL;
1122
1123 if (psc->GSUB_Table)
1124 {
1125 const GSUB_Script *script;
1126 const GSUB_LangSys *language;
1127 int attempt = 2;
1128
1129 do
1130 {
1131 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1132 attempt--;
1133 if (script)
1134 {
1135 if (psc->userLang != 0)
1136 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1137 else
1138 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1139 if (language)
1140 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1141 }
1142 } while(attempt && !feature);
1143
1144 /* try in the default (latin) table */
1145 if (!feature)
1146 {
1147 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1148 if (script)
1149 {
1150 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1151 if (language)
1152 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1153 }
1154 }
1155 }
1156
1157 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1158
1159 psc->feature_count++;
1160
1161 if (psc->features)
1162 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1163 else
1164 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1165
1166 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1167 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1168 psc->features[psc->feature_count - 1].feature = feature;
1169 return feature;
1170 }
1171
1172 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)
1173 {
1174 const GSUB_Feature *feature;
1175
1176 feature = load_GSUB_feature(hdc, psa, psc, feat);
1177 if (!feature)
1178 return GSUB_E_NOFEATURE;
1179
1180 TRACE("applying feature %s\n",feat);
1181 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1182 }
1183
1184 static VOID *load_gsub_table(HDC hdc)
1185 {
1186 VOID* GSUB_Table = NULL;
1187 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1188 if (length != GDI_ERROR)
1189 {
1190 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1191 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1192 TRACE("Loaded GSUB table of %i bytes\n",length);
1193 }
1194 return GSUB_Table;
1195 }
1196
1197 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)
1198 {
1199 WORD *glyphs;
1200 INT glyph_count = count;
1201 INT rc;
1202
1203 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1204 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1205 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1206 if (rc > GSUB_E_NOGLYPH)
1207 rc = count - glyph_count;
1208 else
1209 rc = 0;
1210
1211 HeapFree(GetProcessHeap(),0,glyphs);
1212 return rc;
1213 }
1214
1215 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1216 {
1217 int offset;
1218 WORD class = 0;
1219 const GDEF_ClassDefFormat1 *cf1;
1220
1221 if (!header)
1222 return 0;
1223
1224 offset = GET_BE_WORD(header->GlyphClassDef);
1225 if (!offset)
1226 return 0;
1227
1228 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1229 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1230 {
1231 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1232 {
1233 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1234 if (index < GET_BE_WORD(cf1->GlyphCount))
1235 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1236 }
1237 }
1238 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1239 {
1240 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1241 int i, top;
1242 top = GET_BE_WORD(cf2->ClassRangeCount);
1243 for (i = 0; i < top; i++)
1244 {
1245 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1246 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1247 {
1248 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1249 break;
1250 }
1251 }
1252 }
1253 else
1254 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1255
1256 return class;
1257 }
1258
1259 static VOID *load_gdef_table(HDC hdc)
1260 {
1261 VOID* GDEF_Table = NULL;
1262 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1263 if (length != GDI_ERROR)
1264 {
1265 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1266 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1267 TRACE("Loaded GDEF table of %i bytes\n",length);
1268 }
1269 return GDEF_Table;
1270 }
1271
1272 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
1273 {
1274 int i;
1275
1276 if (!psc->GDEF_Table)
1277 psc->GDEF_Table = load_gdef_table(hdc);
1278
1279 for (i = 0; i < cGlyphs; i++)
1280 {
1281 WORD class;
1282 int char_count = 0;
1283 int k;
1284
1285 for (k = 0; k < cChars; k++)
1286 if (pwLogClust[k] == i)
1287 char_count++;
1288
1289 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1290
1291 switch (class)
1292 {
1293 case 0:
1294 case BaseGlyph:
1295 pGlyphProp[i].sva.fClusterStart = 1;
1296 pGlyphProp[i].sva.fDiacritic = 0;
1297 pGlyphProp[i].sva.fZeroWidth = 0;
1298 break;
1299 case LigatureGlyph:
1300 pGlyphProp[i].sva.fClusterStart = 1;
1301 pGlyphProp[i].sva.fDiacritic = 0;
1302 pGlyphProp[i].sva.fZeroWidth = 0;
1303 break;
1304 case MarkGlyph:
1305 pGlyphProp[i].sva.fClusterStart = 0;
1306 pGlyphProp[i].sva.fDiacritic = 1;
1307 pGlyphProp[i].sva.fZeroWidth = 1;
1308 break;
1309 case ComponentGlyph:
1310 pGlyphProp[i].sva.fClusterStart = 0;
1311 pGlyphProp[i].sva.fDiacritic = 0;
1312 pGlyphProp[i].sva.fZeroWidth = 0;
1313 break;
1314 default:
1315 ERR("Unknown glyph class %i\n",class);
1316 pGlyphProp[i].sva.fClusterStart = 1;
1317 pGlyphProp[i].sva.fDiacritic = 0;
1318 pGlyphProp[i].sva.fZeroWidth = 0;
1319 }
1320
1321 if (char_count == 0)
1322 pGlyphProp[i].sva.fClusterStart = 0;
1323 }
1324 }
1325
1326 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1327 {
1328 int i;
1329
1330 for (i = 0; i < cGlyphs; i++)
1331 {
1332 if (!pGlyphProp[i].sva.fClusterStart)
1333 {
1334 int j;
1335 for (j = 0; j < cChars; j++)
1336 {
1337 if (pwLogClust[j] == i)
1338 {
1339 int k = j;
1340 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1341 k-=1;
1342 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1343 pwLogClust[j] = pwLogClust[k];
1344 }
1345 }
1346 }
1347 }
1348 }
1349
1350 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1351 {
1352 if (changeCount == 0)
1353 return;
1354 else
1355 {
1356 int i;
1357 int target_glyph = nextIndex - write_dir;
1358 int seeking_glyph;
1359 int target_index = -1;
1360 int replacing_glyph = -1;
1361 int changed = 0;
1362 int top_logclust = 0;
1363
1364 if (changeCount > 0)
1365 {
1366 if (write_dir > 0)
1367 target_glyph = nextIndex - changeCount;
1368 else
1369 target_glyph = nextIndex + (changeCount + 1);
1370 }
1371
1372 seeking_glyph = target_glyph;
1373 for (i = 0; i < chars; i++)
1374 if (pwLogClust[i] > top_logclust)
1375 top_logclust = pwLogClust[i];
1376
1377 do {
1378 if (write_dir > 0)
1379 for (i = 0; i < chars; i++)
1380 {
1381 if (pwLogClust[i] == seeking_glyph)
1382 {
1383 target_index = i;
1384 break;
1385 }
1386 }
1387 else
1388 for (i = chars - 1; i >= 0; i--)
1389 {
1390 if (pwLogClust[i] == seeking_glyph)
1391 {
1392 target_index = i;
1393 break;
1394 }
1395 }
1396 if (target_index == -1)
1397 seeking_glyph ++;
1398 }
1399 while (target_index == -1 && seeking_glyph <= top_logclust);
1400
1401 if (target_index == -1)
1402 {
1403 ERR("Unable to find target glyph\n");
1404 return;
1405 }
1406
1407 if (changeCount < 0)
1408 {
1409 /* merge glyphs */
1410 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1411 {
1412 if (pwLogClust[i] == target_glyph)
1413 continue;
1414 if(pwLogClust[i] == replacing_glyph)
1415 pwLogClust[i] = target_glyph;
1416 else
1417 {
1418 changed--;
1419 if (changed >= changeCount)
1420 {
1421 replacing_glyph = pwLogClust[i];
1422 pwLogClust[i] = target_glyph;
1423 }
1424 else
1425 break;
1426 }
1427 }
1428
1429 /* renumber trailing indexes*/
1430 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1431 {
1432 if (pwLogClust[i] != target_glyph)
1433 pwLogClust[i] += changeCount;
1434 }
1435 }
1436 else
1437 {
1438 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1439 pwLogClust[i] += changeCount;
1440 }
1441 }
1442 }
1443
1444 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 )
1445 {
1446 if (psc->GSUB_Table)
1447 {
1448 const GSUB_Feature *feature;
1449 const GSUB_LookupList *lookup;
1450 const GSUB_Header *header = psc->GSUB_Table;
1451 int lookup_index, lookup_count;
1452
1453 feature = load_GSUB_feature(hdc, psa, psc, feat);
1454 if (!feature)
1455 return GSUB_E_NOFEATURE;
1456
1457 TRACE("applying feature %s\n",debugstr_an(feat,4));
1458 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1459 lookup_count = GET_BE_WORD(feature->LookupCount);
1460 TRACE("%i lookups\n", lookup_count);
1461 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1462 {
1463 int i;
1464
1465 if (write_dir > 0)
1466 i = 0;
1467 else
1468 i = *pcGlyphs-1;
1469 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1470 while(i < *pcGlyphs && i >= 0)
1471 {
1472 INT nextIndex;
1473 INT prevCount = *pcGlyphs;
1474
1475 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1476 if (*pcGlyphs != prevCount)
1477 {
1478 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1479 i = nextIndex;
1480 }
1481 else
1482 i+=write_dir;
1483 }
1484 }
1485 return *pcGlyphs;
1486 }
1487 return GSUB_E_NOFEATURE;
1488 }
1489
1490 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1491 {
1492 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1493 }
1494
1495 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1496 {
1497 if (i + delta < 0)
1498 return 0;
1499 if ( i+ delta >= cchLen)
1500 return 0;
1501
1502 i += delta;
1503
1504 return chars[i];
1505 }
1506
1507 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1508 {
1509 if (i + delta < 0)
1510 {
1511 if (psa->fLinkBefore)
1512 return jtR;
1513 else
1514 return jtU;
1515 }
1516 if ( i+ delta >= cchLen)
1517 {
1518 if (psa->fLinkAfter)
1519 return jtL;
1520 else
1521 return jtU;
1522 }
1523
1524 i += delta;
1525
1526 if (context_type[i] == jtT)
1527 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1528 else
1529 return context_type[i];
1530 }
1531
1532 static inline BOOL right_join_causing(CHAR joining_type)
1533 {
1534 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1535 }
1536
1537 static inline BOOL left_join_causing(CHAR joining_type)
1538 {
1539 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1540 }
1541
1542 static inline BOOL word_break_causing(WCHAR chr)
1543 {
1544 /* we are working within a string of characters already guareented to
1545 be within one script, Syriac, so we do not worry about any character
1546 other than the space character outside of that range */
1547 return (chr == 0 || chr == 0x20 );
1548 }
1549
1550 /*
1551 * ContextualShape_Arabic
1552 */
1553 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1554 {
1555 CHAR *context_type;
1556 INT *context_shape;
1557 INT dirR, dirL;
1558 int i;
1559
1560 if (*pcGlyphs != cChars)
1561 {
1562 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1563 return;
1564 }
1565
1566 if (!psa->fLogicalOrder && psa->fRTL)
1567 {
1568 dirR = 1;
1569 dirL = -1;
1570 }
1571 else
1572 {
1573 dirR = -1;
1574 dirL = 1;
1575 }
1576
1577 if (!psc->GSUB_Table)
1578 psc->GSUB_Table = load_gsub_table(hdc);
1579
1580 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1581 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1582
1583 for (i = 0; i < cChars; i++)
1584 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1585
1586 for (i = 0; i < cChars; i++)
1587 {
1588 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1589 context_shape[i] = Xr;
1590 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1591 context_shape[i] = Xl;
1592 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)))
1593 context_shape[i] = Xm;
1594 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1595 context_shape[i] = Xr;
1596 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1597 context_shape[i] = Xl;
1598 else
1599 context_shape[i] = Xn;
1600 }
1601
1602 /* Contextual Shaping */
1603 i = 0;
1604 while(i < *pcGlyphs)
1605 {
1606 BOOL shaped = FALSE;
1607
1608 if (psc->GSUB_Table)
1609 {
1610 INT nextIndex;
1611 INT prevCount = *pcGlyphs;
1612 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1613 if (nextIndex > GSUB_E_NOGLYPH)
1614 {
1615 i = nextIndex;
1616 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1617 }
1618 shaped = (nextIndex > GSUB_E_NOGLYPH);
1619 }
1620
1621 if (!shaped)
1622 {
1623 if (context_shape[i] == Xn)
1624 {
1625 WORD newGlyph = pwOutGlyphs[i];
1626 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1627 {
1628 /* fall back to presentation form B */
1629 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1630 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1631 pwOutGlyphs[i] = newGlyph;
1632 }
1633 }
1634 i++;
1635 }
1636 }
1637
1638 HeapFree(GetProcessHeap(),0,context_shape);
1639 HeapFree(GetProcessHeap(),0,context_type);
1640 }
1641
1642 /*
1643 * ContextualShape_Syriac
1644 */
1645
1646 #define ALAPH 0x710
1647 #define DALATH 0x715
1648 #define RISH 0x72A
1649
1650 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1651 {
1652 CHAR *context_type;
1653 INT *context_shape;
1654 INT dirR, dirL;
1655 int i;
1656
1657 if (*pcGlyphs != cChars)
1658 {
1659 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1660 return;
1661 }
1662
1663 if (!psa->fLogicalOrder && psa->fRTL)
1664 {
1665 dirR = 1;
1666 dirL = -1;
1667 }
1668 else
1669 {
1670 dirR = -1;
1671 dirL = 1;
1672 }
1673
1674 if (!psc->GSUB_Table)
1675 psc->GSUB_Table = load_gsub_table(hdc);
1676
1677 if (!psc->GSUB_Table)
1678 return;
1679
1680 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1681 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1682
1683 for (i = 0; i < cChars; i++)
1684 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1685
1686 for (i = 0; i < cChars; i++)
1687 {
1688 if (pwcChars[i] == ALAPH)
1689 {
1690 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1691
1692 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1693 context_shape[i] = Afj;
1694 else if ( rchar != DALATH && rchar != RISH &&
1695 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1696 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1697 context_shape[i] = Afn;
1698 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1699 context_shape[i] = Afx;
1700 else
1701 context_shape[i] = Xn;
1702 }
1703 else if (context_type[i] == jtR &&
1704 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;
1716 }
1717
1718 /* Contextual Shaping */
1719 i = 0;
1720 while(i < *pcGlyphs)
1721 {
1722 INT nextIndex;
1723 INT prevCount = *pcGlyphs;
1724 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1725 if (nextIndex > GSUB_E_NOGLYPH)
1726 {
1727 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1728 i = nextIndex;
1729 }
1730 else
1731 i++;
1732 }
1733
1734 HeapFree(GetProcessHeap(),0,context_shape);
1735 HeapFree(GetProcessHeap(),0,context_type);
1736 }
1737
1738 /*
1739 * ContextualShape_Phags_pa
1740 */
1741
1742 #define phags_pa_CANDRABINDU 0xA873
1743 #define phags_pa_START 0xA840
1744 #define phags_pa_END 0xA87F
1745
1746 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1747 {
1748 INT *context_shape;
1749 INT dirR, dirL;
1750 int i;
1751
1752 if (*pcGlyphs != cChars)
1753 {
1754 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1755 return;
1756 }
1757
1758 if (!psa->fLogicalOrder && psa->fRTL)
1759 {
1760 dirR = 1;
1761 dirL = -1;
1762 }
1763 else
1764 {
1765 dirR = -1;
1766 dirL = 1;
1767 }
1768
1769 if (!psc->GSUB_Table)
1770 psc->GSUB_Table = load_gsub_table(hdc);
1771
1772 if (!psc->GSUB_Table)
1773 return;
1774
1775 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1776
1777 for (i = 0; i < cChars; i++)
1778 {
1779 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1780 {
1781 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1782 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1783 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1784 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1785
1786 if (jrchar && jlchar)
1787 context_shape[i] = Xm;
1788 else if (jrchar)
1789 context_shape[i] = Xr;
1790 else if (jlchar)
1791 context_shape[i] = Xl;
1792 else
1793 context_shape[i] = Xn;
1794 }
1795 else
1796 context_shape[i] = -1;
1797 }
1798
1799 /* Contextual Shaping */
1800 i = 0;
1801 while(i < *pcGlyphs)
1802 {
1803 if (context_shape[i] >= 0)
1804 {
1805 INT nextIndex;
1806 INT prevCount = *pcGlyphs;
1807 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1808 if (nextIndex > GSUB_E_NOGLYPH)
1809 {
1810 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1811 i = nextIndex;
1812 }
1813 else
1814 i++;
1815 }
1816 else
1817 i++;
1818 }
1819
1820 HeapFree(GetProcessHeap(),0,context_shape);
1821 }
1822
1823 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1824 {
1825 int i;
1826
1827 /* Replace */
1828 pwOutChars[cWalk] = replacements[0];
1829 cWalk=cWalk+1;
1830
1831 /* Insert */
1832 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1833 {
1834 int j;
1835 for (j = *pcChars; j > cWalk; j--)
1836 pwOutChars[j] = pwOutChars[j-1];
1837 *pcChars= *pcChars+1;
1838 pwOutChars[cWalk] = replacements[i];
1839 cWalk = cWalk+1;
1840 }
1841 }
1842
1843 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1844 {
1845 int i;
1846 int cWalk;
1847
1848 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1849 {
1850 for (i = 0; vowels[i].base != 0x0; i++)
1851 {
1852 if (pwOutChars[cWalk] == vowels[i].base)
1853 {
1854 int o = 0;
1855 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1856 if (vowels[i].parts[1]) { cWalk++; o++; }
1857 if (vowels[i].parts[2]) { cWalk++; o++; }
1858 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1859 break;
1860 }
1861 }
1862 }
1863 }
1864
1865 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1866 {
1867 int i;
1868 int offset = 0;
1869 int cWalk;
1870
1871 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1872 {
1873 for (i = 0; consonants[i].output!= 0x0; i++)
1874 {
1875 int j;
1876 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1877 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1878 break;
1879
1880 if (consonants[i].parts[j]==0x0) /* matched all */
1881 {
1882 int k;
1883 j--;
1884 pwOutChars[cWalk] = consonants[i].output;
1885 for(k = cWalk+1; k < *pcChars - j; k++)
1886 pwOutChars[k] = pwOutChars[k+j];
1887 *pcChars = *pcChars - j;
1888 for (k = j ; k > 0; k--)
1889 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1890 offset += j;
1891 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1892 pwLogClust[k]--;
1893 break;
1894 }
1895 }
1896 cWalk++;
1897 }
1898 }
1899
1900 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1901 {
1902 if (s->ralf >= 0)
1903 {
1904 int j;
1905 WORD Ra = pwChar[s->start];
1906 WORD H = pwChar[s->start+1];
1907
1908 TRACE("Doing reorder of Ra to %i\n",s->base);
1909 for (j = s->start; j < s->base-1; j++)
1910 pwChar[j] = pwChar[j+2];
1911 pwChar[s->base-1] = Ra;
1912 pwChar[s->base] = H;
1913
1914 s->ralf = s->base-1;
1915 s->base -= 2;
1916 }
1917 }
1918
1919 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1920 {
1921 if (s->ralf >= 0)
1922 {
1923 int j,loc;
1924 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1925 WORD Ra = pwChar[s->start];
1926 WORD H = pwChar[s->start+1];
1927 for (loc = s->end; loc > stop; loc--)
1928 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1929 break;
1930
1931 TRACE("Doing reorder of Ra to %i\n",loc);
1932 for (j = s->start; j < loc-1; j++)
1933 pwChar[j] = pwChar[j+2];
1934 pwChar[loc-1] = Ra;
1935 pwChar[loc] = H;
1936
1937 s->ralf = loc-1;
1938 s->base -= 2;
1939 if (s->blwf >= 0) s->blwf -= 2;
1940 if (s->pref >= 0) s->pref -= 2;
1941 }
1942 }
1943
1944 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1945 {
1946 if (s->ralf >= 0)
1947 {
1948 int j;
1949 WORD Ra = pwChar[s->start];
1950 WORD H = pwChar[s->start+1];
1951
1952 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1953 for (j = s->start; j < s->end-1; j++)
1954 pwChar[j] = pwChar[j+2];
1955 pwChar[s->end-1] = Ra;
1956 pwChar[s->end] = H;
1957
1958 s->ralf = s->end-1;
1959 s->base -= 2;
1960 if (s->blwf >= 0) s->blwf -= 2;
1961 if (s->pref >= 0) s->pref -= 2;
1962 }
1963 }
1964
1965 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1966 {
1967 int i;
1968
1969 /* reorder Matras */
1970 if (s->end > s->base)
1971 {
1972 for (i = 1; i <= s->end-s->base; i++)
1973 {
1974 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1975 {
1976 int j;
1977 WCHAR c = pwChar[s->base+i];
1978 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1979 for (j = s->base+i; j > s->base; j--)
1980 pwChar[j] = pwChar[j-1];
1981 pwChar[s->base] = c;
1982
1983 if (s->ralf >= s->base) s->ralf++;
1984 if (s->blwf >= s->base) s->blwf++;
1985 if (s->pref >= s->base) s->pref++;
1986 s->base ++;
1987 }
1988 }
1989 }
1990 }
1991
1992 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1993 {
1994 int i;
1995
1996 /* reorder Matras */
1997 if (s->end > s->base)
1998 {
1999 for (i = 1; i <= s->end-s->base; i++)
2000 {
2001 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2002 {
2003 int j;
2004 WCHAR c = pwChar[s->base+i];
2005 TRACE("Doing reorder of %x to %i\n",c,s->start);
2006 for (j = s->base+i; j > s->start; j--)
2007 pwChar[j] = pwChar[j-1];
2008 pwChar[s->start] = c;
2009
2010 if (s->ralf >= 0) s->ralf++;
2011 if (s->blwf >= 0) s->blwf++;
2012 if (s->pref >= 0) s->pref++;
2013 s->base ++;
2014 }
2015 }
2016 }
2017 }
2018
2019 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2020 {
2021 if (s->blwf >= 0 && g->blwf > g->base)
2022 {
2023 int j,loc;
2024 int g_offset;
2025 for (loc = s->end; loc > s->blwf; loc--)
2026 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2027 break;
2028
2029 g_offset = (loc - s->blwf) - 1;
2030
2031 if (loc != s->blwf)
2032 {
2033 WORD blwf = glyphs[g->blwf];
2034 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2035 /* do not care about the pwChar array anymore, just the glyphs */
2036 for (j = 0; j < g_offset; j++)
2037 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2038 glyphs[g->blwf + g_offset] = blwf;
2039 }
2040 }
2041 }
2042
2043 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2044 {
2045 int i;
2046
2047 /* reorder previously moved Matras to correct position*/
2048 for (i = s->start; i < s->base; i++)
2049 {
2050 if (lexical(pwChar[i]) == lex_Matra_pre)
2051 {
2052 int j;
2053 int g_start = g->start + i - s->start;
2054 if (g_start < g->base -1 )
2055 {
2056 WCHAR og = glyphs[g_start];
2057 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2058 for (j = g_start; j < g->base-1; j++)
2059 glyphs[j] = glyphs[j+1];
2060 glyphs[g->base-1] = og;
2061 }
2062 }
2063 }
2064 }
2065
2066 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2067 {
2068 if (s->pref >= 0 && g->pref > g->base)
2069 {
2070 int j;
2071 WCHAR og = glyphs[g->pref];
2072 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2073 for (j = g->pref; j > g->base; j--)
2074 glyphs[j] = glyphs[j-1];
2075 glyphs[g->base] = og;
2076 }
2077 }
2078
2079 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2080 {
2081 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2082 if (s->start == s->base && s->base == s->end) return;
2083 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2084
2085 Reorder_Ra_follows_base(pwChar, s, lexical);
2086 Reorder_Matra_precede_base(pwChar, s, lexical);
2087 }
2088
2089 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2090 {
2091 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2092 if (s->start == s->base && s->base == s->end) return;
2093 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2094
2095 Reorder_Ra_follows_matra(pwChar, s, lexical);
2096 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2097 }
2098
2099 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2100 {
2101 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2102 if (s->start == s->base && s->base == s->end) return;
2103 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2104
2105 Reorder_Ra_follows_base(pwChar, s, lexical);
2106 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2107 }
2108
2109 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2110 {
2111 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2112 if (s->start == s->base && s->base == s->end) return;
2113 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2114
2115 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2116 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2117 }
2118
2119 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2120 {
2121 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2122 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2123 if (s->start == s->base && s->base == s->end) return;
2124 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2125
2126 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2127 }
2128
2129 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2130 {
2131 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2132 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2133 if (s->start == s->base && s->base == s->end) return;
2134 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2135
2136 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2137 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2138 }
2139
2140
2141 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2142 {
2143 if (shift == 0)
2144 return;
2145
2146 if (glyph_index->start > index)
2147 glyph_index->start += shift;
2148 if (glyph_index->base > index)
2149 glyph_index->base+= shift;
2150 if (glyph_index->end > index)
2151 glyph_index->end+= shift;
2152 if (glyph_index->ralf > index)
2153 glyph_index->ralf+= shift;
2154 if (glyph_index->blwf > index)
2155 glyph_index->blwf+= shift;
2156 if (glyph_index->pref > index)
2157 glyph_index->pref+= shift;
2158 }
2159
2160 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 )
2161 {
2162 int index = glyph_index->start;
2163
2164 if (!feature)
2165 return;
2166
2167 while(index <= glyph_index->end)
2168 {
2169 INT nextIndex;
2170 INT prevCount = *pcGlyphs;
2171 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2172 if (nextIndex > GSUB_E_NOGLYPH)
2173 {
2174 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2175 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2176 index = nextIndex;
2177 }
2178 else
2179 index++;
2180 }
2181 }
2182
2183 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2184 {
2185 int i = 0;
2186 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)))))
2187 i++;
2188 if (index + i <= end-1)
2189 return index + i;
2190 else
2191 return -1;
2192 }
2193
2194 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)
2195 {
2196 INT index, nextIndex;
2197 INT count,g_offset;
2198
2199 count = syllable->base - syllable->start;
2200
2201 g_offset = 0;
2202 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2203 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2204 {
2205 INT prevCount = *pcGlyphs;
2206 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2207 if (nextIndex > GSUB_E_NOGLYPH)
2208 {
2209 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2210 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2211 g_offset += (*pcGlyphs - prevCount);
2212 }
2213
2214 index+=2;
2215 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2216 }
2217 }
2218
2219 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)
2220 {
2221 INT nextIndex;
2222 INT prevCount = *pcGlyphs;
2223
2224 if (syllable->ralf >= 0)
2225 {
2226 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2227 if (nextIndex > GSUB_E_NOGLYPH)
2228 {
2229 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2230 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2231 }
2232 }
2233 }
2234
2235 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2236 {
2237 int i = 0;
2238 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2239 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2240 is_consonant(lexical(pwChars[index+i+1])))))
2241 i++;
2242 if (index + i <= end-1)
2243 return index+i;
2244 else
2245 return -1;
2246 }
2247
2248 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)
2249 {
2250 INT index, nextIndex;
2251 INT count, g_offset=0;
2252 INT ralf = syllable->ralf;
2253
2254 count = syllable->end - syllable->base;
2255
2256 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2257
2258 while (index >= 0)
2259 {
2260 INT prevCount = *pcGlyphs;
2261 if (ralf >=0 && ralf < index)
2262 {
2263 g_offset--;
2264 ralf = -1;
2265 }
2266
2267 if (!modern)
2268 {
2269 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2270 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2271 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2272 }
2273
2274 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2275 if (nextIndex > GSUB_E_NOGLYPH)
2276 {
2277 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2278 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2279 g_offset += (*pcGlyphs - prevCount);
2280 }
2281 else if (!modern)
2282 {
2283 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2284 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2285 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2286 }
2287
2288 index+=2;
2289 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2290 }
2291 }
2292
2293 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)
2294 {
2295 int c;
2296 int overall_shift = 0;
2297 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2298 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2299 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2300 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2301 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2302 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2303 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2304 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2305 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2306 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2307 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2308 IndicSyllable glyph_indexs;
2309
2310 for (c = 0; c < syllable_count; c++)
2311 {
2312 int old_end;
2313 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2314 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2315 old_end = glyph_indexs.end;
2316
2317 if (locl)
2318 {
2319 TRACE("applying feature locl\n");
2320 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2321 }
2322 if (nukt)
2323 {
2324 TRACE("applying feature nukt\n");
2325 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2326 }
2327 if (akhn)
2328 {
2329 TRACE("applying feature akhn\n");
2330 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2331 }
2332
2333 if (rphf)
2334 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2335 if (rkrf)
2336 {
2337 TRACE("applying feature rkrf\n");
2338 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2339 }
2340 if (pref)
2341 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2342 if (blwf)
2343 {
2344 if (!modern)
2345 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2346
2347 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2348
2349 }
2350 if (half)
2351 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2352 if (pstf)
2353 {
2354 TRACE("applying feature pstf\n");
2355 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2356 }
2357 if (vatu)
2358 {
2359 TRACE("applying feature vatu\n");
2360 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2361 }
2362 if (cjct)
2363 {
2364 TRACE("applying feature cjct\n");
2365 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2366 }
2367
2368 if (second_reorder)
2369 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2370
2371 overall_shift += glyph_indexs.end - old_end;
2372 }
2373 }
2374
2375 static inline int unicode_lex(WCHAR c)
2376 {
2377 int type;
2378
2379 if (!c) return lex_Generic;
2380 if (c == 0x200D) return lex_ZWJ;
2381 if (c == 0x200C) return lex_ZWNJ;
2382 if (c == 0x00A0) return lex_NBSP;
2383
2384 type = get_table_entry( indic_syllabic_table, c );
2385
2386 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2387
2388 switch( type )
2389 {
2390 case 0x0d07: /* Unknown */
2391 case 0x0e07: /* Unknwon */
2392 default: return lex_Generic;
2393 case 0x0001:
2394 case 0x0002:
2395 case 0x0011:
2396 case 0x0012:
2397 case 0x0013:
2398 case 0x0014: return lex_Modifier;
2399 case 0x0003:
2400 case 0x0009:
2401 case 0x000a:
2402 case 0x000b:
2403 case 0x000d:
2404 case 0x000e:
2405 case 0x000f:
2406 case 0x0010: return lex_Consonant;
2407 case 0x0004: return lex_Nukta;
2408 case 0x0005: return lex_Halant;
2409 case 0x0006:
2410 case 0x0008: return lex_Vowel;
2411 case 0x0007:
2412 case 0x0107: return lex_Matra_post;
2413 case 0x0207:
2414 case 0x0307: return lex_Matra_pre;
2415 case 0x0807:
2416 case 0x0907:
2417 case 0x0a07:
2418 case 0x0b07:
2419 case 0x0c07:
2420 case 0x0407: return lex_Composed_Vowel;
2421 case 0x0507: return lex_Matra_above;
2422 case 0x0607: return lex_Matra_below;
2423 case 0x000c: return lex_Ra;
2424 };
2425 }
2426
2427 static int sinhala_lex(WCHAR c)
2428 {
2429 switch (c)
2430 {
2431 case 0x0DDA:
2432 case 0x0DDD:
2433 case 0x0DDC:
2434 case 0x0DDE: return lex_Matra_post;
2435 default:
2436 return unicode_lex(c);
2437 }
2438 }
2439
2440 static const VowelComponents Sinhala_vowels[] = {
2441 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2442 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2443 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2444 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2445 {0x0000, {0x0000,0x0000,0x0}}};
2446
2447 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2448 {
2449 int cCount = cChars;
2450 int i;
2451 WCHAR *input;
2452 IndicSyllable *syllables = NULL;
2453 int syllable_count = 0;
2454
2455 if (*pcGlyphs != cChars)
2456 {
2457 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2458 return;
2459 }
2460
2461 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2462
2463 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2464
2465 /* Step 1: Decompose multi part vowels */
2466 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2467
2468 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2469
2470 /* Step 2: Reorder within Syllables */
2471 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2472 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2473
2474 /* Step 3: Strip dangling joiners */
2475 for (i = 0; i < cCount; i++)
2476 {
2477 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2478 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2479 input[i] = 0x0020;
2480 }
2481
2482 /* Step 4: Base Form application to syllables */
2483 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2484 *pcGlyphs = cCount;
2485 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2486
2487 HeapFree(GetProcessHeap(),0,input);
2488 HeapFree(GetProcessHeap(),0,syllables);
2489 }
2490
2491 static int devanagari_lex(WCHAR c)
2492 {
2493 switch (c)
2494 {
2495 case 0x0930: return lex_Ra;
2496 default:
2497 return unicode_lex(c);
2498 }
2499 }
2500
2501 static const ConsonantComponents Devanagari_consonants[] ={
2502 {{0x0928, 0x093C, 0x00000}, 0x0929},
2503 {{0x0930, 0x093C, 0x00000}, 0x0931},
2504 {{0x0933, 0x093C, 0x00000}, 0x0934},
2505 {{0x0915, 0x093C, 0x00000}, 0x0958},
2506 {{0x0916, 0x093C, 0x00000}, 0x0959},
2507 {{0x0917, 0x093C, 0x00000}, 0x095A},
2508 {{0x091C, 0x093C, 0x00000}, 0x095B},
2509 {{0x0921, 0x093C, 0x00000}, 0x095C},
2510 {{0x0922, 0x093C, 0x00000}, 0x095D},
2511 {{0x092B, 0x093C, 0x00000}, 0x095E},
2512 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2513
2514 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2515 {
2516 int cCount = cChars;
2517 WCHAR *input;
2518 IndicSyllable *syllables = NULL;
2519 int syllable_count = 0;
2520 BOOL modern = get_GSUB_Indic2(psa, psc);
2521
2522 if (*pcGlyphs != cChars)
2523 {
2524 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2525 return;
2526 }
2527
2528 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2529 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2530
2531 /* Step 1: Compose Consonant and Nukta */
2532 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2533 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2534
2535 /* Step 2: Reorder within Syllables */
2536 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2537 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2538 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2539 *pcGlyphs = cCount;
2540
2541 /* Step 3: Base Form application to syllables */
2542 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2543
2544 HeapFree(GetProcessHeap(),0,input);
2545 HeapFree(GetProcessHeap(),0,syllables);
2546 }
2547
2548 static int bengali_lex(WCHAR c)
2549 {
2550 switch (c)
2551 {
2552 case 0x09B0: return lex_Ra;
2553 default:
2554 return unicode_lex(c);
2555 }
2556 }
2557
2558 static const VowelComponents Bengali_vowels[] = {
2559 {0x09CB, {0x09C7,0x09BE,0x0000}},
2560 {0x09CC, {0x09C7,0x09D7,0x0000}},
2561 {0x0000, {0x0000,0x0000,0x0000}}};
2562
2563 static const ConsonantComponents Bengali_consonants[] = {
2564 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2565 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2566 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2567 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2568 {{0x0000,0x0000,0x0000}, 0x0000}};
2569
2570 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2571 {
2572 int cCount = cChars;
2573 WCHAR *input;
2574 IndicSyllable *syllables = NULL;
2575 int syllable_count = 0;
2576 BOOL modern = get_GSUB_Indic2(psa, psc);
2577
2578 if (*pcGlyphs != cChars)
2579 {
2580 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2581 return;
2582 }
2583
2584 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2585 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2586
2587 /* Step 1: Decompose Vowels and Compose Consonents */
2588 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2589 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2590 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2591
2592 /* Step 2: Reorder within Syllables */
2593 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2594 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2595 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2596 *pcGlyphs = cCount;
2597
2598 /* Step 3: Initial form is only applied to the beginning of words */
2599 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2600 {
2601 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2602 {
2603 int index = cCount;
2604 int gCount = 1;
2605 if (index > 0) index++;
2606
2607 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2608 }
2609 }
2610
2611 /* Step 4: Base Form application to syllables */
2612 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2613
2614 HeapFree(GetProcessHeap(),0,input);
2615 HeapFree(GetProcessHeap(),0,syllables);
2616 }
2617
2618 static int gurmukhi_lex(WCHAR c)
2619 {
2620 if (c == 0x0A71)
2621 return lex_Modifier;
2622 else
2623 return unicode_lex(c);
2624 }
2625
2626 static const ConsonantComponents Gurmukhi_consonants[] = {
2627 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2628 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2629 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2630 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2631 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2632 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2633 {{0x0000,0x0000,0x0000}, 0x0000}};
2634
2635 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2636 {
2637 int cCount = cChars;
2638 WCHAR *input;
2639 IndicSyllable *syllables = NULL;
2640 int syllable_count = 0;
2641 BOOL modern = get_GSUB_Indic2(psa, psc);
2642
2643 if (*pcGlyphs != cChars)
2644 {
2645 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2646 return;
2647 }
2648
2649 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2650 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2651
2652 /* Step 1: Compose Consonents */
2653 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2654 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2655
2656 /* Step 2: Reorder within Syllables */
2657 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2658 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2659 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2660 *pcGlyphs = cCount;
2661
2662 /* Step 3: Base Form application to syllables */
2663 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2664
2665 HeapFree(GetProcessHeap(),0,input);
2666 HeapFree(GetProcessHeap(),0,syllables);
2667 }
2668
2669 static int gujarati_lex(WCHAR c)
2670 {
2671 switch (c)
2672 {
2673 case 0x0AB0: return lex_Ra;
2674 default:
2675 return unicode_lex(c);
2676 }
2677 }
2678
2679 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2680 {
2681 int cCount = cChars;
2682 WCHAR *input;
2683 IndicSyllable *syllables = NULL;
2684 int syllable_count = 0;
2685 BOOL modern = get_GSUB_Indic2(psa, psc);
2686
2687 if (*pcGlyphs != cChars)
2688 {
2689 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2690 return;
2691 }
2692
2693 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2694 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2695
2696 /* Step 1: Reorder within Syllables */
2697 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2698 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2699 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2700 *pcGlyphs = cCount;
2701
2702 /* Step 2: Base Form application to syllables */
2703 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2704
2705 HeapFree(GetProcessHeap(),0,input);
2706 HeapFree(GetProcessHeap(),0,syllables);
2707 }
2708
2709 static int oriya_lex(WCHAR c)
2710 {
2711 switch (c)
2712 {
2713 case 0x0B30: return lex_Ra;
2714 default:
2715 return unicode_lex(c);
2716 }
2717 }
2718
2719 static const VowelComponents Oriya_vowels[] = {
2720 {0x0B48, {0x0B47,0x0B56,0x0000}},
2721 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2722 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2723 {0x0000, {0x0000,0x0000,0x0000}}};
2724
2725 static const ConsonantComponents Oriya_consonants[] = {
2726 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2727 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2728 {{0x0000,0x0000,0x0000}, 0x0000}};
2729
2730 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2731 {
2732 int cCount = cChars;
2733 WCHAR *input;
2734 IndicSyllable *syllables = NULL;
2735 int syllable_count = 0;
2736 BOOL modern = get_GSUB_Indic2(psa, psc);
2737
2738 if (*pcGlyphs != cChars)
2739 {
2740 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2741 return;
2742 }
2743
2744 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2745 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2746
2747 /* Step 1: Decompose Vowels and Compose Consonents */
2748 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2749 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2750 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2751
2752 /* Step 2: Reorder within Syllables */
2753 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2754 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2755 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2756 *pcGlyphs = cCount;
2757
2758 /* Step 3: Base Form application to syllables */
2759 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2760
2761 HeapFree(GetProcessHeap(),0,input);
2762 HeapFree(GetProcessHeap(),0,syllables);
2763 }
2764
2765 static int tamil_lex(WCHAR c)
2766 {
2767 return unicode_lex(c);
2768 }
2769
2770 static const VowelComponents Tamil_vowels[] = {
2771 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2772 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2773 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2774 {0x0000, {0x0000,0x0000,0x0000}}};
2775
2776 static const ConsonantComponents Tamil_consonants[] = {
2777 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2778 {{0x0000,0x0000,0x0000}, 0x0000}};
2779
2780 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2781 {
2782 int cCount = cChars;
2783 WCHAR *input;
2784 IndicSyllable *syllables = NULL;
2785 int syllable_count = 0;
2786 BOOL modern = get_GSUB_Indic2(psa, psc);
2787
2788 if (*pcGlyphs != cChars)
2789 {
2790 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2791 return;
2792 }
2793
2794 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2795 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2796
2797 /* Step 1: Decompose Vowels and Compose Consonents */
2798 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2799 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2800 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2801
2802 /* Step 2: Reorder within Syllables */
2803 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2804 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2805 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2806 *pcGlyphs = cCount;
2807
2808 /* Step 3: Base Form application to syllables */
2809 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2810
2811 HeapFree(GetProcessHeap(),0,input);
2812 HeapFree(GetProcessHeap(),0,syllables);
2813 }
2814
2815 static int telugu_lex(WCHAR c)
2816 {
2817 switch (c)
2818 {
2819 case 0x0C43:
2820 case 0x0C44: return lex_Modifier;
2821 default:
2822 return unicode_lex(c);
2823 }
2824 }
2825
2826 static const VowelComponents Telugu_vowels[] = {
2827 {0x0C48, {0x0C46,0x0C56,0x0000}},
2828 {0x0000, {0x0000,0x0000,0x0000}}};
2829
2830 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2831 {
2832 int cCount = cChars;
2833 WCHAR *input;
2834 IndicSyllable *syllables = NULL;
2835 int syllable_count = 0;
2836 BOOL modern = get_GSUB_Indic2(psa, psc);
2837
2838 if (*pcGlyphs != cChars)
2839 {
2840 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2841 return;
2842 }
2843
2844 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2845 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2846
2847 /* Step 1: Decompose Vowels */
2848 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2849 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2850
2851 /* Step 2: Reorder within Syllables */
2852 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2853 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2854 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2855 *pcGlyphs = cCount;
2856
2857 /* Step 3: Base Form application to syllables */
2858 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2859
2860 HeapFree(GetProcessHeap(),0,input);
2861 HeapFree(GetProcessHeap(),0,syllables);
2862 }
2863
2864 static int kannada_lex(WCHAR c)
2865 {
2866 switch (c)
2867 {
2868 case 0x0CB0: return lex_Ra;
2869 default:
2870 return unicode_lex(c);
2871 }
2872 }
2873
2874 static const VowelComponents Kannada_vowels[] = {
2875 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2876 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2877 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2878 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2879 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2880 {0x0000, {0x0000,0x0000,0x0000}}};
2881
2882 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2883 {
2884 int cCount = cChars;
2885 WCHAR *input;
2886 IndicSyllable *syllables = NULL;
2887 int syllable_count = 0;
2888 BOOL modern = get_GSUB_Indic2(psa, psc);
2889
2890 if (*pcGlyphs != cChars)
2891 {
2892 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2893 return;
2894 }
2895
2896 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2897 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2898
2899 /* Step 1: Decompose Vowels */
2900 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2901 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2902
2903 /* Step 2: Reorder within Syllables */
2904 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2905 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2906 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2907 *pcGlyphs = cCount;
2908
2909 /* Step 3: Base Form application to syllables */
2910 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2911
2912 HeapFree(GetProcessHeap(),0,input);
2913 HeapFree(GetProcessHeap(),0,syllables);
2914 }
2915
2916 static int malayalam_lex(WCHAR c)
2917 {
2918 return unicode_lex(c);
2919 }
2920
2921 static const VowelComponents Malayalam_vowels[] = {
2922 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2923 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2924 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2925 {0x0000, {0x0000,0x0000,0x0000}}};
2926
2927 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2928 {
2929 int cCount = cChars;
2930 WCHAR *input;
2931 IndicSyllable *syllables = NULL;
2932 int syllable_count = 0;
2933 BOOL modern = get_GSUB_Indic2(psa, psc);
2934
2935 if (*pcGlyphs != cChars)
2936 {
2937 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2938 return;
2939 }
2940
2941 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2942 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2943
2944 /* Step 1: Decompose Vowels */
2945 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2946 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2947
2948 /* Step 2: Reorder within Syllables */
2949 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2950 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2951 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2952 *pcGlyphs = cCount;
2953
2954 /* Step 3: Base Form application to syllables */
2955 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2956
2957 HeapFree(GetProcessHeap(),0,input);
2958 HeapFree(GetProcessHeap(),0,syllables);
2959 }
2960
2961 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)
2962 {
2963 int i,k;
2964
2965 for (i = 0; i < cGlyphs; i++)
2966 {
2967 int char_index[20];
2968 int char_count = 0;
2969
2970 for (k = 0; k < cChars; k++)
2971 {
2972 if (pwLogClust[k] == i)
2973 {
2974 char_index[char_count] = k;
2975 char_count++;
2976 }
2977 }
2978
2979 if (char_count == 0)
2980 continue;
2981
2982 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2983 {
2984 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2985 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2986 }
2987 else
2988 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2989 }
2990
2991 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2992 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2993 }
2994
2995 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 )
2996 {
2997 int i,k;
2998 int initGlyph, finaGlyph;
2999 INT dirR, dirL;
3000 BYTE *spaces;
3001
3002 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3003 memset(spaces,0,cGlyphs);
3004
3005 if (!psa->fLogicalOrder && psa->fRTL)
3006 {
3007 initGlyph = cGlyphs-1;
3008 finaGlyph = 0;
3009 dirR = 1;
3010 dirL = -1;
3011 }
3012 else
3013 {
3014 initGlyph = 0;
3015 finaGlyph = cGlyphs-1;
3016 dirR = -1;
3017 dirL = 1;
3018 }
3019
3020 for (i = 0; i < cGlyphs; i++)
3021 {
3022 for (k = 0; k < cChars; k++)
3023 if (pwLogClust[k] == i)
3024 {
3025 if (pwcChars[k] == 0x0020)
3026 spaces[i] = 1;
3027 }
3028 }
3029
3030 for (i = 0; i < cGlyphs; i++)
3031 {
3032 int char_index[20];
3033 int char_count = 0;
3034 BOOL isInit, isFinal;
3035
3036 for (k = 0; k < cChars; k++)
3037 {
3038 if (pwLogClust[k] == i)
3039 {
3040 char_index[char_count] = k;
3041 char_count++;
3042 }
3043 }
3044
3045 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3046 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3047
3048 if (char_count == 0)
3049 continue;
3050
3051 if (char_count == 1)
3052 {
3053 if (pwcChars[char_index[0]] == 0x0020) /* space */
3054 {
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3056 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3057 }
3058 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3059 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3060 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3061 {
3062 if (!isInit && !isFinal)
3063 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3064 else if (isInit)
3065 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3066 else
3067 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3068 }
3069 else if (!isInit)
3070 {
3071 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3072 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3073 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3074 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3075 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3076 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3077 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3078 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3079 else
3080 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3081 }
3082 else if (!isInit && !isFinal)
3083 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3084 else
3085 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3086 }
3087 else if (char_count == 2)
3088 {
3089 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3090 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3091 else if (!isInit)
3092 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3093 else
3094 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3095 }
3096 else if (!isInit && !isFinal)
3097 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3098 else
3099 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3100 }
3101
3102 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3103 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3104 HeapFree(GetProcessHeap(),0,spaces);
3105 }
3106
3107 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 )
3108 {
3109 int i,k;
3110 int finaGlyph;
3111 INT dirL;
3112 BYTE *spaces;
3113
3114 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3115 memset(spaces,0,cGlyphs);
3116
3117 if (!psa->fLogicalOrder && psa->fRTL)
3118 {
3119 finaGlyph = 0;
3120 dirL = -1;
3121 }
3122 else
3123 {
3124 finaGlyph = cGlyphs-1;
3125 dirL = 1;
3126 }
3127
3128 for (i = 0; i < cGlyphs; i++)
3129 {
3130 for (k = 0; k < cChars; k++)
3131 if (pwLogClust[k] == i)
3132 {
3133 if (pwcChars[k] == 0x0020)
3134 spaces[i] = 1;
3135 }
3136 }
3137
3138 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3139
3140 for (i = 0; i < cGlyphs; i++)
3141 {
3142 int char_index[20];
3143 int char_count = 0;
3144
3145 for (k = 0; k < cChars; k++)
3146 {
3147 if (pwLogClust[k] == i)
3148 {
3149 char_index[char_count] = k;
3150 char_count++;
3151 }
3152 }
3153
3154 if (char_count == 0)
3155 continue;
3156
3157 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3158 {
3159 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3160 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3161 }
3162 else if (i == finaGlyph)
3163 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3164 else
3165 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3166
3167 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3168 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3169 pGlyphProp[i].sva.fClusterStart = 0;
3170 }
3171
3172 HeapFree(GetProcessHeap(),0,spaces);
3173 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3174
3175 /* Do not allow justification between marks and their base */
3176 for (i = 0; i < cGlyphs; i++)
3177 {
3178 if (!pGlyphProp[i].sva.fClusterStart)
3179 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3180 }
3181 }
3182
3183 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)
3184 {
3185 int i,k;
3186
3187 for (i = 0; i < cGlyphs; i++)
3188 {
3189 int char_index[20];
3190 int char_count = 0;
3191
3192 for (k = 0; k < cChars; k++)
3193 {
3194 if (pwLogClust[k] == i)
3195 {
3196 char_index[char_count] = k;
3197 char_count++;
3198 }
3199 }
3200
3201 if (char_count == 0)
3202 continue;
3203
3204 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3205 {
3206 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3207 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3208 }
3209 else
3210 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3211 }
3212 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3213 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3214 }
3215
3216 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)
3217 {
3218 int i,k;
3219
3220 for (i = 0; i < cGlyphs; i++)
3221 {
3222 int char_index[20];
3223 int char_count = 0;
3224
3225 for (k = 0; k < cChars; k++)
3226 {
3227 if (pwLogClust[k] == i)
3228 {
3229 char_index[char_count] = k;
3230 char_count++;
3231 }
3232 }
3233
3234 if (char_count == 0)
3235 continue;
3236
3237 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3238 {
3239 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3240 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3241 }
3242 else
3243 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3244 }
3245 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3246 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3247
3248 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3249 for (i = 0; i < cGlyphs; i++)
3250 {
3251 if (!pGlyphProp[i].sva.fClusterStart)
3252 {
3253 pGlyphProp[i].sva.fDiacritic = 0;
3254 pGlyphProp[i].sva.fZeroWidth = 0;
3255 }
3256 }
3257 }
3258
3259 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)
3260 {
3261 int i,k;
3262
3263 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3264 for (i = 0; i < cGlyphs; i++)
3265 {
3266 int char_index[20];
3267 int char_count = 0;
3268
3269 for (k = 0; k < cChars; k++)
3270 {
3271 if (pwLogClust[k] == i)
3272 {
3273 char_index[char_count] = k;
3274 char_count++;
3275 }
3276 }
3277
3278 /* Indic scripts do not set fDiacritic or fZeroWidth */
3279 pGlyphProp[i].sva.fDiacritic = FALSE;
3280 pGlyphProp[i].sva.fZeroWidth = FALSE;
3281
3282 if (char_count == 0)
3283 continue;
3284
3285 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3286 {
3287 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3288 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3289 }
3290 else
3291 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3292
3293 pGlyphProp[i].sva.fClusterStart = 0;
3294 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3295 switch (lexical(pwcChars[char_index[k]]))
3296 {
3297 case lex_Matra_pre:
3298 case lex_Matra_post:
3299 case lex_Matra_above:
3300 case lex_Matra_below:
3301 case lex_Modifier:
3302 case lex_Halant:
3303 break;
3304 case lex_ZWJ:
3305 case lex_ZWNJ:
3306 k = char_count;
3307 break;
3308 default:
3309 pGlyphProp[i].sva.fClusterStart = 1;
3310 break;
3311 }
3312 }
3313
3314 if (use_syllables)
3315 {
3316 IndicSyllable *syllables = NULL;
3317 int syllable_count = 0;
3318 BOOL modern = get_GSUB_Indic2(psa, psc);
3319
3320 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3321
3322 for (i = 0; i < syllable_count; i++)
3323 {
3324 int j;
3325 WORD g = pwLogClust[syllables[i].start];
3326 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3327 {
3328 if (pwLogClust[j] != g)
3329 {
3330 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3331 pwLogClust[j] = g;
3332 }
3333 }
3334 }
3335
3336 HeapFree(GetProcessHeap(), 0, syllables);
3337 }
3338
3339 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3340 }
3341
3342 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 )
3343 {
3344 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE);
3345 }
3346
3347 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 )
3348 {
3349 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE);
3350 }
3351
3352 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 )
3353 {
3354 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE);
3355 }
3356
3357 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 )
3358 {
3359 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE);
3360 }
3361
3362 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 )
3363 {
3364 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE);
3365 }
3366
3367 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 )
3368 {
3369 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE);
3370 }
3371
3372 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 )
3373 {
3374 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE);
3375 }
3376
3377 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 )
3378 {
3379 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE);
3380 }
3381
3382 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 )
3383 {
3384 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE);
3385 }
3386
3387 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 )
3388 {
3389 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE);
3390 }
3391
3392 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)
3393 {
3394 if (ShapingData[psa->eScript].charGlyphPropProc)
3395 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3396 else
3397 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3398 }
3399
3400 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3401 {
3402 if (!psc->GSUB_Table)
3403 psc->GSUB_Table = load_gsub_table(hdc);
3404
3405 if (ShapingData[psa->eScript].contextProc)
3406 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3407 }
3408
3409 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)
3410 {
3411 int i;
3412 INT dirL;
3413
3414 if (!rpRangeProperties)
3415 return;
3416
3417 if (!psc->GSUB_Table)
3418 psc->GSUB_Table = load_gsub_table(hdc);
3419
3420 if (!psc->GSUB_Table)
3421 return;
3422
3423 if (!psa->fLogicalOrder && psa->fRTL)
3424 dirL = -1;
3425 else
3426 dirL = 1;
3427
3428 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3429 {
3430 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3431 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3432 }
3433 }
3434
3435 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3436 {
3437 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3438 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3439
3440 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3441 }
3442
3443 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3444 {
3445 const GSUB_Feature *feature;
3446 int i;
3447
3448 if (!ShapingData[psa->eScript].requiredFeatures)
3449 return S_OK;
3450
3451 if (!psc->GSUB_Table)
3452 psc->GSUB_Table = load_gsub_table(hdc);
3453
3454 /* we need to have at least one of the required features */
3455 i = 0;
3456 while (ShapingData[psa->eScript].requiredFeatures[i])
3457 {
3458 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3459 if (feature)
3460 return S_OK;
3461 i++;
3462 }
3463
3464 return USP_E_SCRIPT_NOT_IN_FONT;
3465 }