ReactOS 0.4.15-dev-7674-gc0b4db1
shape.c
Go to the documentation of this file.
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#include <stdlib.h>
23
24#include "windef.h"
25#include "winbase.h"
26#include "wingdi.h"
27#include "winuser.h"
28#include "winnls.h"
29#include "usp10.h"
30#include "winternl.h"
31
32#include "usp10_internal.h"
33
34#include "wine/debug.h"
35#include "wine/heap.h"
36
38
39#define FIRST_ARABIC_CHAR 0x0600
40#define LAST_ARABIC_CHAR 0x06ff
41
43 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44
65
67
68static void ShapeCharGlyphProp_Default( 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);
69static void ShapeCharGlyphProp_Control( 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 );
70static void ShapeCharGlyphProp_Latin( 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 );
71static 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 );
72static void ShapeCharGlyphProp_Hebrew( 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 );
73static 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 );
74static 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 );
75static 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 );
76static 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 );
77static 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 );
78static 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 );
79static 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 );
80static 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 );
81static 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 );
82static 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 );
83static 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 );
84static 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 );
85static 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 );
86static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
87
88extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
89extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
90extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
91
98 jtC
99};
100
102 Xn=0,
106 /* Syriac Alaph */
109 Afx
111
112typedef struct tagVowelComponents
113{
117
119{
123
124typedef void (*second_reorder_function)(const WCHAR *chars, const IndicSyllable *syllable,
125 WORD *glyphs, const IndicSyllable *glyph_index, lexical_function lex);
126
128
129/* the orders of joined_forms and contextual_features need to line up */
130static const char *const contextual_features[] =
131{
132 "isol",
133 "fina",
134 "init",
135 "medi",
136 /* Syriac Alaph */
137 "med2",
138 "fin2",
139 "fin3"
140};
141
143{
144 { MS_MAKE_TAG('c','c','m','p'), 1},
145 { MS_MAKE_TAG('l','o','c','l'), 1},
146};
147
149{
150 { MS_MAKE_TAG('l','o','c','l'), 1},
151 { MS_MAKE_TAG('c','c','m','p'), 1},
152 { MS_MAKE_TAG('l','i','g','a'), 1},
153 { MS_MAKE_TAG('c','l','i','g'), 1},
154};
155
157{
158 { MS_MAKE_TAG('k','e','r','n'), 1},
159 { MS_MAKE_TAG('m','a','r','k'), 1},
160 { MS_MAKE_TAG('m','k','m','k'), 1},
161};
162
164{
165 { MS_MAKE_TAG('r','l','i','g'), 1},
166 { MS_MAKE_TAG('c','a','l','t'), 1},
167 { MS_MAKE_TAG('l','i','g','a'), 1},
168 { MS_MAKE_TAG('d','l','i','g'), 1},
169 { MS_MAKE_TAG('c','s','w','h'), 1},
170 { MS_MAKE_TAG('m','s','e','t'), 1},
171};
172
173static const char *const required_arabic_features[] =
174{
175 "fina",
176 "init",
177 "medi",
178 "rlig",
179 NULL
180};
181
183{
184 { MS_MAKE_TAG('c','u','r','s'), 1},
185 { MS_MAKE_TAG('k','e','r','n'), 1},
186 { MS_MAKE_TAG('m','a','r','k'), 1},
187 { MS_MAKE_TAG('m','k','m','k'), 1},
188};
189
191{
192 { MS_MAKE_TAG('c','c','m','p'), 1},
193 { MS_MAKE_TAG('d','l','i','g'), 0},
194};
195
197{
198 { MS_MAKE_TAG('k','e','r','n'), 1},
199 { MS_MAKE_TAG('m','a','r','k'), 1},
200};
201
203{
204 { MS_MAKE_TAG('r','l','i','g'), 1},
205 { MS_MAKE_TAG('c','a','l','t'), 1},
206 { MS_MAKE_TAG('l','i','g','a'), 1},
207 { MS_MAKE_TAG('d','l','i','g'), 1},
208};
209
210static const char *const required_syriac_features[] =
211{
212 "fina",
213 "fin2",
214 "fin3",
215 "init",
216 "medi",
217 "med2",
218 "rlig",
219 NULL
220};
221
223{
224 { MS_MAKE_TAG('k','e','r','n'), 1},
225 { MS_MAKE_TAG('m','a','r','k'), 1},
226 { MS_MAKE_TAG('m','k','m','k'), 1},
227};
228
230{
231 /* Presentation forms */
232 { MS_MAKE_TAG('b','l','w','s'), 1},
233 { MS_MAKE_TAG('a','b','v','s'), 1},
234 { MS_MAKE_TAG('p','s','t','s'), 1},
235};
236
238{
239 { MS_MAKE_TAG('a','b','v','s'), 1},
240 { MS_MAKE_TAG('b','l','w','s'), 1},
241};
242
244{
245 { MS_MAKE_TAG('a','b','v','m'), 1},
246 { MS_MAKE_TAG('b','l','w','m'), 1},
247};
248
250{
251 { MS_MAKE_TAG('a','b','v','s'), 1},
252 { MS_MAKE_TAG('b','l','w','s'), 1},
253 { MS_MAKE_TAG('c','a','l','t'), 1},
254};
255
257{
258 { MS_MAKE_TAG('c','c','m','p'), 1},
259};
260
262{
263 { MS_MAKE_TAG('k','e','r','n'), 1},
264 { MS_MAKE_TAG('m','a','r','k'), 1},
265 { MS_MAKE_TAG('m','k','m','k'), 1},
266};
267
268static const char *const required_lao_features[] =
269{
270 "ccmp",
271 NULL
272};
273
274static const char *const required_devanagari_features[] =
275{
276 "nukt",
277 "akhn",
278 "rphf",
279 "blwf",
280 "half",
281 "vatu",
282 "pres",
283 "abvs",
284 "blws",
285 "psts",
286 "haln",
287 NULL
288};
289
291{
292 { MS_MAKE_TAG('p','r','e','s'), 1},
293 { MS_MAKE_TAG('a','b','v','s'), 1},
294 { MS_MAKE_TAG('b','l','w','s'), 1},
295 { MS_MAKE_TAG('p','s','t','s'), 1},
296 { MS_MAKE_TAG('h','a','l','n'), 1},
297 { MS_MAKE_TAG('c','a','l','t'), 1},
298};
299
301{
302 { MS_MAKE_TAG('k','e','r','n'), 1},
303 { MS_MAKE_TAG('d','i','s','t'), 1},
304 { MS_MAKE_TAG('a','b','v','m'), 1},
305 { MS_MAKE_TAG('b','l','w','m'), 1},
306};
307
309{
310 { MS_MAKE_TAG('l','i','g','a'), 1},
311 { MS_MAKE_TAG('c','l','i','g'), 1},
312};
313
314static const char *const required_bengali_features[] =
315{
316 "nukt",
317 "akhn",
318 "rphf",
319 "blwf",
320 "half",
321 "vatu",
322 "pstf",
323 "init",
324 "abvs",
325 "blws",
326 "psts",
327 "haln",
328 NULL
329};
330
331static const char *const required_gurmukhi_features[] =
332{
333 "nukt",
334 "akhn",
335 "rphf",
336 "blwf",
337 "half",
338 "pstf",
339 "vatu",
340 "cjct",
341 "pres",
342 "abvs",
343 "blws",
344 "psts",
345 "haln",
346 "calt",
347 NULL
348};
349
350static const char *const required_oriya_features[] =
351{
352 "nukt",
353 "akhn",
354 "rphf",
355 "blwf",
356 "pstf",
357 "cjct",
358 "pres",
359 "abvs",
360 "blws",
361 "psts",
362 "haln",
363 "calt",
364 NULL
365};
366
367static const char *const required_tamil_features[] =
368{
369 "nukt",
370 "akhn",
371 "rphf",
372 "pref",
373 "half",
374 "pres",
375 "abvs",
376 "blws",
377 "psts",
378 "haln",
379 "calt",
380 NULL
381};
382
383static const char *const required_telugu_features[] =
384{
385 "nukt",
386 "akhn",
387 "rphf",
388 "pref",
389 "half",
390 "pstf",
391 "cjct",
392 "pres",
393 "abvs",
394 "blws",
395 "psts",
396 "haln",
397 "calt",
398 NULL
399};
400
402{
403 { MS_MAKE_TAG('p','r','e','s'), 1},
404 { MS_MAKE_TAG('b','l','w','s'), 1},
405 { MS_MAKE_TAG('a','b','v','s'), 1},
406 { MS_MAKE_TAG('p','s','t','s'), 1},
407 { MS_MAKE_TAG('c','l','i','g'), 1},
408};
409
410static const char *const required_khmer_features[] =
411{
412 "pref",
413 "blwf",
414 "abvf",
415 "pstf",
416 "pres",
417 "blws",
418 "abvs",
419 "psts",
420 "clig",
421 NULL
422};
423
425{
426 { MS_MAKE_TAG('d','i','s','t'), 1},
427 { MS_MAKE_TAG('b','l','w','m'), 1},
428 { MS_MAKE_TAG('a','b','v','m'), 1},
429 { MS_MAKE_TAG('m','k','m','k'), 1},
430};
431
433{
434 { MS_MAKE_TAG('c','c','m','p'), 1},
435 { MS_MAKE_TAG('l','o','c','l'), 1},
436 { MS_MAKE_TAG('c','a','l','t'), 1},
437 { MS_MAKE_TAG('l','i','g','a'), 1},
438};
439
441{
442 { MS_MAKE_TAG('c','c','m','p'), 1},
443 { MS_MAKE_TAG('l','o','c','l'), 1},
444 { MS_MAKE_TAG('c','a','l','t'), 1},
445 { MS_MAKE_TAG('r','l','i','g'), 1},
446};
447
448typedef struct ScriptShapeDataTag {
451 const char *const *requiredFeatures;
456
457/* in order of scripts */
459{
460 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
504 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
506 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
511 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
514 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
516 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
524 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
526 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
527 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
528 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
529 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
530 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
531 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
532 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
533 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
534 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
535 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
536 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
537 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
538 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
542};
543
545
547 WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count)
548{
549 int i;
550 int out_index = GSUB_E_NOGLYPH;
551
552 TRACE("%i lookups\n", feature->lookup_count);
553 for (i = 0; i < feature->lookup_count; i++)
554 {
555 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
556 if (out_index != GSUB_E_NOGLYPH)
557 break;
558 }
559 if (out_index == GSUB_E_NOGLYPH)
560 TRACE("lookups found no glyphs\n");
561 else
562 {
563 int out2;
564 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
565 if (out2!=GSUB_E_NOGLYPH)
566 out_index = out2;
567 }
568 return out_index;
569}
570
572 const ScriptCache *script_cache, BOOL try_new)
573{
575
576 if (script_cache->userScript)
577 {
578 if (try_new && ShapingData[psa->eScript].newOtTag
579 && script_cache->userScript == scriptInformation[psa->eScript].scriptTag)
580 return ShapingData[psa->eScript].newOtTag;
581
582 return script_cache->userScript;
583 }
584
585 if (try_new && ShapingData[psa->eScript].newOtTag)
586 return ShapingData[psa->eScript].newOtTag;
587
588 if (scriptInformation[psa->eScript].scriptTag)
589 return scriptInformation[psa->eScript].scriptTag;
590
591 /*
592 * fall back to the font charset
593 */
595 switch (charset)
596 {
597 case ANSI_CHARSET:
598 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
599 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
600 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
601 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
602 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
603 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
604 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
605 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
606 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
607 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
608 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
609 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
610 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
611 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
612 default: return MS_MAKE_TAG('l','a','t','n');
613 }
614}
615
616static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
617{
619
620 if (psc->GSUB_Table || psc->GPOS_Table)
621 {
622 int attempt = 2;
624 OPENTYPE_TAG language;
625 OPENTYPE_TAG script = 0x00000000;
626 int cTags;
627
628 do
629 {
630 script = get_opentype_script(hdc,psa,psc,(attempt==2));
631 if (psc->userLang != 0)
632 language = psc->userLang;
633 else
634 language = MS_MAKE_TAG('d','f','l','t');
635 attempt--;
636
637 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
638
639 } while(attempt && !feature);
640
641 /* try in the default (latin) table */
642 if (!feature)
643 {
644 if (!script)
645 script = MS_MAKE_TAG('l','a','t','n');
646 OpenType_GetFontFeatureTags(psc, script, MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
647 }
648 }
649
650 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
651 return feature;
652}
653
654static 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)
655{
657
659 if (!feature)
660 return GSUB_E_NOFEATURE;
661
662 TRACE("applying feature %s\n",feat);
663 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
664}
665
667{
668 VOID* GSUB_Table = NULL;
669 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
670 if (length != GDI_ERROR)
671 {
672 GSUB_Table = heap_alloc(length);
673 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
674 TRACE("Loaded GSUB table of %i bytes\n",length);
675 }
676 return GSUB_Table;
677}
678
680{
681 VOID* GPOS_Table = NULL;
682 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
683 if (length != GDI_ERROR)
684 {
685 GPOS_Table = heap_alloc(length);
686 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
687 TRACE("Loaded GPOS table of %i bytes\n",length);
688 }
689 return GPOS_Table;
690}
691
693{
694 VOID* GDEF_Table = NULL;
695 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
696 if (length != GDI_ERROR)
697 {
698 GDEF_Table = heap_alloc(length);
699 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
700 TRACE("Loaded GDEF table of %i bytes\n",length);
701 }
702 return GDEF_Table;
703}
704
706{
707 if (!psc->GSUB_Table)
708 psc->GSUB_Table = load_gsub_table(hdc);
709 if (!psc->GPOS_Table)
710 psc->GPOS_Table = load_gpos_table(hdc);
711 if (!psc->GDEF_Table)
712 psc->GDEF_Table = load_gdef_table(hdc);
713}
714
716 const WCHAR *chars, int write_dir, int count, const char *feature)
717{
718 WORD *glyphs;
719 INT glyph_count = count;
720 INT rc;
721
722 glyphs = heap_calloc(count, 2 * sizeof(*glyphs));
723 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
724 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
725 if (rc > GSUB_E_NOGLYPH)
726 rc = count - glyph_count;
727 else
728 rc = 0;
729
731 return rc;
732}
733
734static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
735{
736 int i;
737
738 for (i = 0; i < cGlyphs; i++)
739 {
740 if (!pGlyphProp[i].sva.fClusterStart)
741 {
742 int j;
743 for (j = 0; j < cChars; j++)
744 {
745 if (pwLogClust[j] == i)
746 {
747 int k = j;
748 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
749 k-=1;
750 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
752 }
753 }
754 }
755 }
756}
757
758static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
759{
760 if (changeCount == 0)
761 return;
762 else
763 {
764 int cluster_dir = pwLogClust[0] < pwLogClust[chars-1] ? 1 : -1;
765 int i;
766 int target_glyph = nextIndex - write_dir;
767 int target_index = -1;
768 int replacing_glyph = -1;
769 int changed = 0;
770
771 if (changeCount > 0)
772 {
773 if (write_dir > 0)
774 target_glyph = nextIndex - changeCount;
775 else
776 target_glyph = nextIndex + (changeCount + 1);
777 }
778
779 target_index = USP10_FindGlyphInLogClust(pwLogClust, chars, target_glyph);
780 if (target_index == -1)
781 {
782 ERR("Unable to find target glyph\n");
783 return;
784 }
785
786 if (changeCount < 0)
787 {
788 /* merge glyphs */
789 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
790 {
791 if (pwLogClust[i] == target_glyph)
792 continue;
793 if(pwLogClust[i] == replacing_glyph)
794 pwLogClust[i] = target_glyph;
795 else
796 {
797 changed--;
798 if (changed >= changeCount)
799 {
800 replacing_glyph = pwLogClust[i];
801 pwLogClust[i] = target_glyph;
802 }
803 else
804 break;
805 }
806 }
807
808 /* renumber trailing indexes */
809 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
810 {
811 if (pwLogClust[i] != target_glyph)
812 pwLogClust[i] += changeCount;
813 }
814 }
815 else
816 {
817 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
818 pwLogClust[i] += changeCount;
819 }
820 }
821}
822
824{
825 if (psc->GSUB_Table)
826 {
828 int lookup_index;
829
831 if (!feature)
832 return GSUB_E_NOFEATURE;
833
834 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
835 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
836 {
837 int i;
838
839 if (write_dir > 0)
840 i = 0;
841 else
842 i = *pcGlyphs-1;
843 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
844 while(i < *pcGlyphs && i >= 0)
845 {
846 INT nextIndex;
847 INT prevCount = *pcGlyphs;
848
849 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
850 if (*pcGlyphs != prevCount)
851 {
852 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
853 i = nextIndex;
854 }
855 else
856 i+=write_dir;
857 }
858 }
859 return *pcGlyphs;
860 }
861 return GSUB_E_NOFEATURE;
862}
863
865 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance,
866 const LoadedFeature *feature, const WORD *glyphs, int glyph_count, GOFFSET *goffset)
867{
868 int dir = analysis->fLogicalOrder && analysis->fRTL ? -1 : 1;
869 unsigned int start_idx, i, j;
870
871 TRACE("%i lookups\n", feature->lookup_count);
872
873 start_idx = dir < 0 ? glyph_count - 1 : 0;
874 for (i = 0; i < feature->lookup_count; i++)
875 {
876 for (j = 0; j < glyph_count; )
877 j += OpenType_apply_GPOS_lookup(psc, otm, logfont, analysis, advance,
878 feature->lookups[i], glyphs, start_idx + dir * j, glyph_count, goffset);
879 }
880}
881
883{
885 HRESULT hr;
886 int count = 0;
887
889
890 return(SUCCEEDED(hr));
891}
892
893static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
894{
895 int i;
896 for (i = *pcGlyphs; i>=index; i--)
897 pwGlyphs[i+1] = pwGlyphs[i];
898 pwGlyphs[index] = glyph;
899 *pcGlyphs = *pcGlyphs+1;
900 if (write_dir < 0)
901 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
902 else
903 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
904}
905
907{
908 CHAR *context_type;
909 int i,g;
910 WCHAR invalid = 0x25cc;
911 WORD invalid_glyph;
912
913 context_type = heap_alloc(cChars);
914
915 /* Mark invalid combinations */
916 for (i = 0; i < cChars; i++)
917 context_type[i] = lex(pwcChars[i]);
918
919 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
920 for (i = 1, g=1; i < cChars - 1; i++, g++)
921 {
922 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
923 {
924 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
925 g++;
926 }
927 }
928
929 heap_free(context_type);
930}
931
933{
934 int i;
935 for (i=0; i < cChars; i++)
936 {
937 switch (pwcChars[i])
938 {
939 case 0x000A:
940 case 0x000D:
941 pwOutGlyphs[i] = psc->sfp.wgBlank;
942 break;
943 default:
944 if (pwcChars[i] < 0x1C)
945 pwOutGlyphs[i] = psc->sfp.wgDefault;
946 else
947 pwOutGlyphs[i] = psc->sfp.wgBlank;
948 }
949 }
950}
951
952static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
953{
954 if (i + delta < 0)
955 return 0;
956 if ( i+ delta >= cchLen)
957 return 0;
958
959 i += delta;
960
961 return chars[i];
962}
963
964static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
965{
966 if (i + delta < 0)
967 {
968 if (psa->fLinkBefore)
969 return jtR;
970 else
971 return jtU;
972 }
973 if ( i+ delta >= cchLen)
974 {
975 if (psa->fLinkAfter)
976 return jtL;
977 else
978 return jtU;
979 }
980
981 i += delta;
982
983 if (context_type[i] == jtT)
984 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
985 else
986 return context_type[i];
987}
988
989static inline BOOL right_join_causing(CHAR joining_type)
990{
991 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
992}
993
994static inline BOOL left_join_causing(CHAR joining_type)
995{
996 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
997}
998
999static inline BOOL word_break_causing(WCHAR chr)
1000{
1001 /* we are working within a string of characters already guareented to
1002 be within one script, Syriac, so we do not worry about any character
1003 other than the space character outside of that range */
1004 return (chr == 0 || chr == 0x20 );
1005}
1006
1008{
1009 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1010
1011 switch(c)
1012 {
1013 case 0x064B:
1014 case 0x064C:
1015 case 0x064E:
1016 case 0x064F:
1017 case 0x0652:
1018 case 0x0657:
1019 case 0x0658:
1020 case 0x06E1: return Arab_DIAC1;
1021 case 0x064D:
1022 case 0x0650:
1023 case 0x0656: return Arab_DIAC2;
1024 case 0x0651: return Arab_DIAC3;
1025 case 0x0610:
1026 case 0x0611:
1027 case 0x0612:
1028 case 0x0613:
1029 case 0x0614:
1030 case 0x0659:
1031 case 0x06D6:
1032 case 0x06DC:
1033 case 0x06DF:
1034 case 0x06E0:
1035 case 0x06E2:
1036 case 0x06E4:
1037 case 0x06E7:
1038 case 0x06E8:
1039 case 0x06EB:
1040 case 0x06EC: return Arab_DIAC4;
1041 case 0x06E3:
1042 case 0x06EA:
1043 case 0x06ED: return Arab_DIAC5;
1044 case 0x0670: return Arab_DIAC6;
1045 case 0x0653: return Arab_DIAC7;
1046 case 0x0655:
1047 case 0x0654: return Arab_DIAC8;
1048 default: return Arab_Norm;
1049 }
1050}
1051
1052/*
1053 * ContextualShape_Arabic
1054 */
1056{
1057 CHAR *context_type;
1058 INT *context_shape;
1059 INT dirR, dirL;
1060 int i;
1061 int char_index;
1062 int glyph_index;
1063
1064 if (*pcGlyphs != cChars)
1065 {
1066 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1067 return;
1068 }
1069
1070 if (psa->fLogicalOrder && psa->fRTL)
1071 {
1072 dirR = -1;
1073 dirL = 1;
1074 }
1075 else
1076 {
1077 dirR = 1;
1078 dirL = -1;
1079 }
1080
1082
1083 context_type = heap_alloc(cChars);
1084 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1085
1086 for (i = 0; i < cChars; i++)
1087 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1088
1089 for (i = 0; i < cChars; i++)
1090 {
1091 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1092 context_shape[i] = Xr;
1093 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1094 context_shape[i] = Xl;
1095 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)))
1096 context_shape[i] = Xm;
1097 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1098 context_shape[i] = Xr;
1099 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1100 context_shape[i] = Xl;
1101 else
1102 context_shape[i] = Xn;
1103 }
1104
1105 /* Contextual Shaping */
1106 if (dirL > 0)
1107 char_index = glyph_index = 0;
1108 else
1109 char_index = glyph_index = cChars-1;
1110
1111 while(char_index < cChars && char_index >= 0)
1112 {
1113 BOOL shaped = FALSE;
1114
1115 if (psc->GSUB_Table)
1116 {
1117 INT nextIndex, offset = 0;
1118 INT prevCount = *pcGlyphs;
1119
1120 /* Apply CCMP first */
1121 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1122
1123 if (prevCount != *pcGlyphs)
1124 {
1125 offset = *pcGlyphs - prevCount;
1126 if (dirL < 0)
1127 glyph_index -= offset * dirL;
1128 }
1129
1130 /* Apply the contextual feature */
1131 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1132
1133 if (nextIndex > GSUB_E_NOGLYPH)
1134 {
1135 UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1136 char_index += dirL;
1137 if (!offset)
1138 glyph_index = nextIndex;
1139 else
1140 {
1141 offset = *pcGlyphs - prevCount;
1142 glyph_index += dirL * (offset + 1);
1143 }
1144 shaped = TRUE;
1145 }
1146 else if (nextIndex == GSUB_E_NOGLYPH)
1147 {
1148 char_index += dirL;
1149 glyph_index += dirL;
1150 shaped = TRUE;
1151 }
1152 }
1153
1154 if (!shaped)
1155 {
1156 if (context_shape[char_index] == Xn)
1157 {
1158 WORD newGlyph = pwOutGlyphs[glyph_index];
1159 if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
1160 {
1161 /* fall back to presentation form B */
1162 WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
1163 if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1164 pwOutGlyphs[glyph_index] = newGlyph;
1165 }
1166 }
1167 char_index += dirL;
1168 glyph_index += dirL;
1169 }
1170 }
1171
1172 heap_free(context_shape);
1173 heap_free(context_type);
1174
1176}
1177
1179{
1180 enum {Hebr_Norm=0, Hebr_DIAC, Hebr_CANT1, Hebr_CANT2, Hebr_CANT3, Hebr_CANT4, Hebr_CANT5, Hebr_CANT6, Hebr_CANT7, Hebr_CANT8, Hebr_CANT9, Hebr_CANT10, Hebr_DAGESH, Hebr_DOTABV, Hebr_HOLAM, Hebr_METEG, Hebr_PATAH, Hebr_QAMATS, Hebr_RAFE, Hebr_SHINSIN};
1181
1182 switch(c)
1183 {
1184 case 0x05B0:
1185 case 0x05B1:
1186 case 0x05B2:
1187 case 0x05B3:
1188 case 0x05B4:
1189 case 0x05B5:
1190 case 0x05B6:
1191 case 0x05BB: return Hebr_DIAC;
1192 case 0x0599:
1193 case 0x05A1:
1194 case 0x05A9:
1195 case 0x05AE: return Hebr_CANT1;
1196 case 0x0597:
1197 case 0x05A8:
1198 case 0x05AC: return Hebr_CANT2;
1199 case 0x0592:
1200 case 0x0593:
1201 case 0x0594:
1202 case 0x0595:
1203 case 0x05A7:
1204 case 0x05AB: return Hebr_CANT3;
1205 case 0x0598:
1206 case 0x059C:
1207 case 0x059E:
1208 case 0x059F: return Hebr_CANT4;
1209 case 0x059D:
1210 case 0x05A0: return Hebr_CANT5;
1211 case 0x059B:
1212 case 0x05A5: return Hebr_CANT6;
1213 case 0x0591:
1214 case 0x05A3:
1215 case 0x05A6: return Hebr_CANT7;
1216 case 0x0596:
1217 case 0x05A4:
1218 case 0x05AA: return Hebr_CANT8;
1219 case 0x059A:
1220 case 0x05AD: return Hebr_CANT9;
1221 case 0x05AF: return Hebr_CANT10;
1222 case 0x05BC: return Hebr_DAGESH;
1223 case 0x05C4: return Hebr_DOTABV;
1224 case 0x05B9: return Hebr_HOLAM;
1225 case 0x05BD: return Hebr_METEG;
1226 case 0x05B7: return Hebr_PATAH;
1227 case 0x05B8: return Hebr_QAMATS;
1228 case 0x05BF: return Hebr_RAFE;
1229 case 0x05C1:
1230 case 0x05C2: return Hebr_SHINSIN;
1231 default: return Hebr_Norm;
1232 }
1233}
1234
1236{
1237 INT dirL;
1238
1239 if (*pcGlyphs != cChars)
1240 {
1241 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1242 return;
1243 }
1244
1245 if (!psa->fLogicalOrder && psa->fRTL)
1246 dirL = -1;
1247 else
1248 dirL = 1;
1249
1251}
1252
1253/*
1254 * ContextualShape_Syriac
1255 */
1256
1258{
1259 enum {Syriac_Norm=0, Syriac_DIAC1, Syriac_DIAC2, Syriac_DIAC3, Syriac_DIAC4, Syriac_DIAC5, Syriac_DIAC6, Syriac_DIAC7, Syriac_DIAC8, Syriac_DIAC9, Syriac_DIAC10, Syriac_DIAC11, Syriac_DIAC12, Syriac_DIAC13, Syriac_DIAC14, Syriac_DIAC15, Syriac_DIAC16, Syriac_DIAC17};
1260
1261 switch(c)
1262 {
1263 case 0x730:
1264 case 0x733:
1265 case 0x736:
1266 case 0x73A:
1267 case 0x73D: return Syriac_DIAC1;
1268 case 0x731:
1269 case 0x734:
1270 case 0x737:
1271 case 0x73B:
1272 case 0x73E: return Syriac_DIAC2;
1273 case 0x740:
1274 case 0x749:
1275 case 0x74A: return Syriac_DIAC3;
1276 case 0x732:
1277 case 0x735:
1278 case 0x73F: return Syriac_DIAC4;
1279 case 0x738:
1280 case 0x739:
1281 case 0x73C: return Syriac_DIAC5;
1282 case 0x741:
1283 case 0x30A: return Syriac_DIAC6;
1284 case 0x742:
1285 case 0x325: return Syriac_DIAC7;
1286 case 0x747:
1287 case 0x303: return Syriac_DIAC8;
1288 case 0x748:
1289 case 0x32D:
1290 case 0x32E:
1291 case 0x330:
1292 case 0x331: return Syriac_DIAC9;
1293 case 0x308: return Syriac_DIAC10;
1294 case 0x304: return Syriac_DIAC11;
1295 case 0x307: return Syriac_DIAC12;
1296 case 0x323: return Syriac_DIAC13;
1297 case 0x743: return Syriac_DIAC14;
1298 case 0x744: return Syriac_DIAC15;
1299 case 0x745: return Syriac_DIAC16;
1300 case 0x746: return Syriac_DIAC17;
1301 default: return Syriac_Norm;
1302 }
1303}
1304
1305#define ALAPH 0x710
1306#define DALATH 0x715
1307#define RISH 0x72A
1308
1310{
1311 CHAR *context_type;
1312 INT *context_shape;
1313 INT dirR, dirL;
1314 int i;
1315 int char_index;
1316 int glyph_index;
1317
1318 if (*pcGlyphs != cChars)
1319 {
1320 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1321 return;
1322 }
1323
1324 if (!psa->fLogicalOrder && psa->fRTL)
1325 {
1326 dirR = 1;
1327 dirL = -1;
1328 }
1329 else
1330 {
1331 dirR = -1;
1332 dirL = 1;
1333 }
1334
1336
1337 if (!psc->GSUB_Table)
1338 return;
1339
1340 context_type = heap_alloc(cChars);
1341 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1342
1343 for (i = 0; i < cChars; i++)
1344 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1345
1346 for (i = 0; i < cChars; i++)
1347 {
1348 if (pwcChars[i] == ALAPH)
1349 {
1350 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1351
1353 context_shape[i] = Afj;
1354 else if ( rchar != DALATH && rchar != RISH &&
1355!left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1357 context_shape[i] = Afn;
1358 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1359 context_shape[i] = Afx;
1360 else
1361 context_shape[i] = Xn;
1362 }
1363 else if (context_type[i] == jtR &&
1365 context_shape[i] = Xr;
1366 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1367 context_shape[i] = Xl;
1368 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)))
1369 context_shape[i] = Xm;
1370 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1371 context_shape[i] = Xr;
1372 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1373 context_shape[i] = Xl;
1374 else
1375 context_shape[i] = Xn;
1376 }
1377
1378 /* Contextual Shaping */
1379 if (dirL > 0)
1380 char_index = glyph_index = 0;
1381 else
1382 char_index = glyph_index = cChars-1;
1383
1384 while(char_index < cChars && char_index >= 0)
1385 {
1386 INT nextIndex, offset = 0;
1387 INT prevCount = *pcGlyphs;
1388
1389 /* Apply CCMP first */
1390 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1391
1392 if (prevCount != *pcGlyphs)
1393 {
1394 offset = *pcGlyphs - prevCount;
1395 if (dirL < 0)
1396 glyph_index -= offset * dirL;
1397 }
1398
1399 /* Apply the contextual feature */
1400 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1401 if (nextIndex > GSUB_E_NOGLYPH)
1402 {
1403 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1404 char_index += dirL;
1405 if (!offset)
1406 glyph_index = nextIndex;
1407 else
1408 {
1409 offset = *pcGlyphs - prevCount;
1410 glyph_index += dirL * (offset + 1);
1411 }
1412 }
1413 else
1414 {
1415 char_index += dirL;
1416 glyph_index += dirL;
1417 }
1418 }
1419
1420 heap_free(context_shape);
1421 heap_free(context_type);
1422
1424}
1425
1427{
1428 enum {Thaana_Norm=0, Thaana_FILI};
1429
1430 switch(c)
1431 {
1432 case 0x7A6:
1433 case 0x7A7:
1434 case 0x7A8:
1435 case 0x7A9:
1436 case 0x7AA:
1437 case 0x7AB:
1438 case 0x7AC:
1439 case 0x7AD:
1440 case 0x7AE:
1441 case 0x7AF: return Thaana_FILI;
1442 default: return Thaana_Norm;
1443 }
1444}
1445
1447{
1448 INT dirL;
1449
1450 if (*pcGlyphs != cChars)
1451 {
1452 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1453 return;
1454 }
1455
1456 if (!psa->fLogicalOrder && psa->fRTL)
1457 dirL = -1;
1458 else
1459 dirL = 1;
1460
1462}
1463
1464/*
1465 * ContextualShape_Phags_pa
1466 */
1467
1468#define phags_pa_CANDRABINDU 0xA873
1469#define phags_pa_START 0xA840
1470#define phags_pa_END 0xA87F
1471
1473{
1474 INT *context_shape;
1475 INT dirR, dirL;
1476 int i;
1477 int char_index;
1478 int glyph_index;
1479
1480 if (*pcGlyphs != cChars)
1481 {
1482 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1483 return;
1484 }
1485
1486 if (!psa->fLogicalOrder && psa->fRTL)
1487 {
1488 dirR = 1;
1489 dirL = -1;
1490 }
1491 else
1492 {
1493 dirR = -1;
1494 dirL = 1;
1495 }
1496
1498
1499 if (!psc->GSUB_Table)
1500 return;
1501
1502 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1503
1504 for (i = 0; i < cChars; i++)
1505 {
1507 {
1508 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1509 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1510 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1511 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1512
1513 if (jrchar && jlchar)
1514 context_shape[i] = Xm;
1515 else if (jrchar)
1516 context_shape[i] = Xr;
1517 else if (jlchar)
1518 context_shape[i] = Xl;
1519 else
1520 context_shape[i] = Xn;
1521 }
1522 else
1523 context_shape[i] = -1;
1524 }
1525
1526 /* Contextual Shaping */
1527 if (dirL > 0)
1528 char_index = glyph_index = 0;
1529 else
1530 char_index = glyph_index = cChars-1;
1531
1532 while(char_index < cChars && char_index >= 0)
1533 {
1534 if (context_shape[char_index] >= 0)
1535 {
1536 INT nextIndex;
1537 INT prevCount = *pcGlyphs;
1538 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1539
1540 if (nextIndex > GSUB_E_NOGLYPH)
1541 {
1542 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1543 glyph_index = nextIndex;
1544 char_index += dirL;
1545 }
1546 else
1547 {
1548 char_index += dirL;
1549 glyph_index += dirL;
1550 }
1551 }
1552 else
1553 {
1554 char_index += dirL;
1555 glyph_index += dirL;
1556 }
1557 }
1558
1559 heap_free(context_shape);
1560}
1561
1563{
1564 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1565
1566 switch(c)
1567 {
1568 case 0xE31:
1569 case 0xE34:
1570 case 0xE35:
1571 case 0xE36:
1572 case 0xE37: return Thai_ABOVE1;
1573 case 0xE47:
1574 case 0xE4D: return Thai_ABOVE2;
1575 case 0xE48:
1576 case 0xE49:
1577 case 0xE4A:
1578 case 0xE4B: return Thai_ABOVE3;
1579 case 0xE4C:
1580 case 0xE4E: return Thai_ABOVE4;
1581 case 0xE38:
1582 case 0xE39: return Thai_BELOW1;
1583 case 0xE3A: return Thai_BELOW2;
1584 case 0xE33: return Thai_AM;
1585 default: return Thai_Norm;
1586 }
1587}
1588
1590{
1591 INT dirL;
1592
1593 if (*pcGlyphs != cChars)
1594 {
1595 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1596 return;
1597 }
1598
1599 if (!psa->fLogicalOrder && psa->fRTL)
1600 dirL = -1;
1601 else
1602 dirL = 1;
1603
1605}
1606
1608{
1609 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1610
1611 switch(c)
1612 {
1613 case 0xEB1:
1614 case 0xEB4:
1615 case 0xEB5:
1616 case 0xEB6:
1617 case 0xEB7:
1618 case 0xEBB:
1619 case 0xECD: return Lao_ABOVE1;
1620 case 0xEC8:
1621 case 0xEC9:
1622 case 0xECA:
1623 case 0xECB:
1624 case 0xECC: return Lao_ABOVE2;
1625 case 0xEBC: return Lao_BELOW1;
1626 case 0xEB8:
1627 case 0xEB9: return Lao_BELOW2;
1628 case 0xEB3: return Lao_AM;
1629 default: return Lao_Norm;
1630 }
1631}
1632
1634{
1635 INT dirL;
1636
1637 if (*pcGlyphs != cChars)
1638 {
1639 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1640 return;
1641 }
1642
1643 if (!psa->fLogicalOrder && psa->fRTL)
1644 dirL = -1;
1645 else
1646 dirL = 1;
1647
1649}
1650
1651static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1652{
1653 int i;
1654
1655 /* Replace */
1656 pwOutChars[cWalk] = replacements[0];
1657 cWalk=cWalk+1;
1658
1659 /* Insert */
1660 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1661 {
1662 int j;
1663 for (j = *pcChars; j > cWalk; j--)
1664 pwOutChars[j] = pwOutChars[j-1];
1665 *pcChars= *pcChars+1;
1666 pwOutChars[cWalk] = replacements[i];
1667 cWalk = cWalk+1;
1668 }
1669}
1670
1671static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1672{
1673 int i;
1674 int cWalk;
1675
1676 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1677 {
1678 for (i = 0; vowels[i].base != 0x0; i++)
1679 {
1680 if (pwOutChars[cWalk] == vowels[i].base)
1681 {
1682 int o = 0;
1683 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1684 if (vowels[i].parts[1]) { cWalk++; o++; }
1685 if (vowels[i].parts[2]) { cWalk++; o++; }
1686 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1687 break;
1688 }
1689 }
1690 }
1691}
1692
1693static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1694{
1695 int i;
1696 int offset = 0;
1697 int cWalk;
1698
1699 for (cWalk = 0; cWalk < *pcChars; cWalk += 2)
1700 {
1701 for (i = 0; consonants[i].output!= 0x0; i++)
1702 {
1703 int j;
1704 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1705 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1706 break;
1707
1708 if (consonants[i].parts[j]==0x0) /* matched all */
1709 {
1710 int k;
1711 j--;
1712 pwOutChars[cWalk] = consonants[i].output;
1713 for(k = cWalk+1; k < *pcChars - j; k++)
1714 pwOutChars[k] = pwOutChars[k+j];
1715 *pcChars = *pcChars - j;
1716 for (k = j ; k > 0; k--)
1717 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1718 offset += j;
1719 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1720 pwLogClust[k]--;
1721 break;
1722 }
1723 }
1724 }
1725}
1726
1728{
1729 if (s->ralf >= 0)
1730 {
1731 int j;
1732 WORD Ra = pwChar[s->start];
1733 WORD H = pwChar[s->start+1];
1734
1735 TRACE("Doing reorder of Ra to %i\n",s->base);
1736 for (j = s->start; j < s->base-1; j++)
1737 pwChar[j] = pwChar[j+2];
1738 pwChar[s->base-1] = Ra;
1739 pwChar[s->base] = H;
1740
1741 s->ralf = s->base-1;
1742 s->base -= 2;
1743 }
1744}
1745
1747{
1748 if (s->ralf >= 0)
1749 {
1750 int j,loc;
1751 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1752 WORD Ra = pwChar[s->start];
1753 WORD H = pwChar[s->start+1];
1754 for (loc = s->end; loc > stop; loc--)
1755 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1756 break;
1757
1758 TRACE("Doing reorder of Ra to %i\n",loc);
1759 for (j = s->start; j < loc-1; j++)
1760 pwChar[j] = pwChar[j+2];
1761 pwChar[loc-1] = Ra;
1762 pwChar[loc] = H;
1763
1764 s->ralf = loc-1;
1765 s->base -= 2;
1766 if (s->blwf >= 0) s->blwf -= 2;
1767 if (s->pref >= 0) s->pref -= 2;
1768 }
1769}
1770
1772{
1773 if (s->ralf >= 0)
1774 {
1775 int j;
1776 WORD Ra = pwChar[s->start];
1777 WORD H = pwChar[s->start+1];
1778
1779 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1780 for (j = s->start; j < s->end-1; j++)
1781 pwChar[j] = pwChar[j+2];
1782 pwChar[s->end-1] = Ra;
1783 pwChar[s->end] = H;
1784
1785 s->ralf = s->end-1;
1786 s->base -= 2;
1787 if (s->blwf >= 0) s->blwf -= 2;
1788 if (s->pref >= 0) s->pref -= 2;
1789 }
1790}
1791
1793{
1794 int i;
1795
1796 /* reorder Matras */
1797 if (s->end > s->base)
1798 {
1799 for (i = 1; i <= s->end-s->base; i++)
1800 {
1801 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1802 {
1803 int j;
1804 WCHAR c = pwChar[s->base+i];
1805 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1806 for (j = s->base+i; j > s->base; j--)
1807 pwChar[j] = pwChar[j-1];
1808 pwChar[s->base] = c;
1809
1810 if (s->ralf >= s->base) s->ralf++;
1811 if (s->blwf >= s->base) s->blwf++;
1812 if (s->pref >= s->base) s->pref++;
1813 s->base ++;
1814 }
1815 }
1816 }
1817}
1818
1820{
1821 int i;
1822
1823 /* reorder Matras */
1824 if (s->end > s->base)
1825 {
1826 for (i = 1; i <= s->end-s->base; i++)
1827 {
1828 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1829 {
1830 int j;
1831 WCHAR c = pwChar[s->base+i];
1832 TRACE("Doing reorder of %x to %i\n",c,s->start);
1833 for (j = s->base+i; j > s->start; j--)
1834 pwChar[j] = pwChar[j-1];
1835 pwChar[s->start] = c;
1836
1837 if (s->ralf >= 0) s->ralf++;
1838 if (s->blwf >= 0) s->blwf++;
1839 if (s->pref >= 0) s->pref++;
1840 s->base ++;
1841 }
1842 }
1843 }
1844}
1845
1847 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1848{
1849 if (s->blwf >= 0 && g->blwf > g->base)
1850 {
1851 int j,loc;
1852 int g_offset;
1853 for (loc = s->end; loc > s->blwf; loc--)
1854 if (lexical(chars[loc]) == lex_Matra_below || lexical(chars[loc]) == lex_Matra_above
1855 || lexical(chars[loc]) == lex_Matra_post)
1856 break;
1857
1858 g_offset = (loc - s->blwf) - 1;
1859
1860 if (loc != s->blwf)
1861 {
1862 WORD blwf = glyphs[g->blwf];
1863 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1864 /* do not care about the pwChar array anymore, just the glyphs */
1865 for (j = 0; j < g_offset; j++)
1866 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1867 glyphs[g->blwf + g_offset] = blwf;
1868 }
1869 }
1870}
1871
1873 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1874{
1875 int i;
1876
1877 /* reorder previously moved Matras to correct position*/
1878 for (i = s->start; i < s->base; i++)
1879 {
1880 if (lexical(chars[i]) == lex_Matra_pre)
1881 {
1882 int j;
1883 int g_start = g->start + i - s->start;
1884 if (g_start < g->base -1 )
1885 {
1886 WCHAR og = glyphs[g_start];
1887 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1888 for (j = g_start; j < g->base-1; j++)
1889 glyphs[j] = glyphs[j+1];
1890 glyphs[g->base-1] = og;
1891 }
1892 }
1893 }
1894}
1895
1897 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1898{
1899 if (s->pref >= 0 && g->pref > g->base)
1900 {
1901 int j;
1902 WCHAR og = glyphs[g->pref];
1903 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1904 for (j = g->pref; j > g->base; j--)
1905 glyphs[j] = glyphs[j-1];
1906 glyphs[g->base] = og;
1907 }
1908}
1909
1911{
1912 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1913 if (s->start == s->base && s->base == s->end) return;
1914 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1915
1916 Reorder_Ra_follows_base(pwChar, s, lexical);
1917 Reorder_Matra_precede_base(pwChar, s, lexical);
1918}
1919
1921{
1922 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1923 if (s->start == s->base && s->base == s->end) return;
1924 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1925
1926 Reorder_Ra_follows_matra(pwChar, s, lexical);
1927 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1928}
1929
1931{
1932 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1933 if (s->start == s->base && s->base == s->end) return;
1934 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1935
1936 Reorder_Ra_follows_base(pwChar, s, lexical);
1937 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1938}
1939
1941{
1942 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1943 if (s->start == s->base && s->base == s->end) return;
1944 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1945
1946 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1947 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1948}
1949
1950static void SecondReorder_Like_Telugu(const WCHAR *chars, const IndicSyllable *s,
1951 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1952{
1953 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1954 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1955 if (s->start == s->base && s->base == s->end) return;
1956 if (lexical(chars[s->base]) == lex_Vowel) return;
1957
1958 SecondReorder_Blwf_follows_matra(chars, s, glyphs, g, lexical);
1959}
1960
1961static void SecondReorder_Like_Tamil(const WCHAR *chars, const IndicSyllable *s,
1962 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1963{
1964 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1965 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1966 if (s->start == s->base && s->base == s->end) return;
1967 if (lexical(chars[s->base]) == lex_Vowel) return;
1968
1969 SecondReorder_Matra_precede_base(chars, s, glyphs, g, lexical);
1971}
1972
1973
1975{
1976 if (shift == 0)
1977 return;
1978
1979 if (glyph_index->start > index)
1980 glyph_index->start += shift;
1981 if (glyph_index->base > index)
1982 glyph_index->base+= shift;
1983 if (glyph_index->end > index)
1984 glyph_index->end+= shift;
1985 if (glyph_index->ralf > index)
1986 glyph_index->ralf+= shift;
1987 if (glyph_index->blwf > index)
1988 glyph_index->blwf+= shift;
1989 if (glyph_index->pref > index)
1990 glyph_index->pref+= shift;
1991}
1992
1994{
1995 int index = glyph_index->start;
1996
1997 if (!feature)
1998 return;
1999
2000 while(index <= glyph_index->end)
2001 {
2002 INT nextIndex;
2003 INT prevCount = *pcGlyphs;
2004 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2005 if (nextIndex > GSUB_E_NOGLYPH)
2006 {
2007 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2008 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2009 index = nextIndex;
2010 }
2011 else
2012 index++;
2013 }
2014}
2015
2017{
2018 int i = 0;
2019 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)))))
2020 i++;
2021 if (index + i <= end-1)
2022 return index + i;
2023 else
2024 return -1;
2025}
2026
2028{
2029 INT index, nextIndex;
2030 INT count,g_offset;
2031
2032 count = syllable->base - syllable->start;
2033
2034 g_offset = 0;
2035 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2036 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2037 {
2038 INT prevCount = *pcGlyphs;
2039 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2040 if (nextIndex > GSUB_E_NOGLYPH)
2041 {
2042 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2043 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2044 g_offset += (*pcGlyphs - prevCount);
2045 }
2046
2047 index+=2;
2048 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2049 }
2050}
2051
2053{
2054 INT nextIndex;
2055 INT prevCount = *pcGlyphs;
2056
2057 if (syllable->ralf >= 0)
2058 {
2059 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2060 if (nextIndex > GSUB_E_NOGLYPH)
2061 {
2062 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2063 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2064 }
2065 }
2066}
2067
2069{
2070 int i = 0;
2071 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2072 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2073 is_consonant(lexical(pwChars[index+i+1])))))
2074 i++;
2075 if (index + i <= end-1)
2076 return index+i;
2077 else
2078 return -1;
2079}
2080
2081static 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)
2082{
2083 INT index, nextIndex;
2084 INT count, g_offset=0;
2085 INT ralf = syllable->ralf;
2086
2087 count = syllable->end - syllable->base;
2088
2089 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2090
2091 while (index >= 0)
2092 {
2093 INT prevCount = *pcGlyphs;
2094 if (ralf >=0 && ralf < index)
2095 {
2096 g_offset--;
2097 ralf = -1;
2098 }
2099
2100 if (!modern)
2101 {
2102 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2103 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2104 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2105 }
2106
2107 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2108 if (nextIndex > GSUB_E_NOGLYPH)
2109 {
2110 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2111 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2112 g_offset += (*pcGlyphs - prevCount);
2113 }
2114 else if (!modern)
2115 {
2116 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2117 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2118 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2119 }
2120
2121 index+=2;
2122 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2123 }
2124}
2125
2127{
2128 int c;
2129 int overall_shift = 0;
2130 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2133 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2135 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2136 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2137 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2138 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2139 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2140 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2141 IndicSyllable glyph_indexs;
2142
2143 for (c = 0; c < syllable_count; c++)
2144 {
2145 int old_end;
2146 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2147 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2148 old_end = glyph_indexs.end;
2149
2150 if (locl)
2151 {
2152 TRACE("applying feature locl\n");
2153 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2154 }
2155 if (nukt)
2156 {
2157 TRACE("applying feature nukt\n");
2158 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2159 }
2160 if (akhn)
2161 {
2162 TRACE("applying feature akhn\n");
2163 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2164 }
2165
2166 if (rphf)
2167 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2168 if (rkrf)
2169 {
2170 TRACE("applying feature rkrf\n");
2171 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2172 }
2173 if (pref)
2174 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2175 if (blwf)
2176 {
2177 if (!modern)
2178 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2179
2180 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2181
2182 }
2183 if (half)
2184 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2185 if (pstf)
2186 {
2187 TRACE("applying feature pstf\n");
2188 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2189 }
2190 if (vatu)
2191 {
2192 TRACE("applying feature vatu\n");
2193 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2194 }
2195 if (cjct)
2196 {
2197 TRACE("applying feature cjct\n");
2198 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2199 }
2200
2201 if (second_reorder)
2202 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2203
2204 overall_shift += glyph_indexs.end - old_end;
2205 }
2206}
2207
2208static inline int unicode_lex(WCHAR c)
2209{
2210 int type;
2211
2212 if (!c) return lex_Generic;
2213 if (c == 0x200D) return lex_ZWJ;
2214 if (c == 0x200C) return lex_ZWNJ;
2215 if (c == 0x00A0) return lex_NBSP;
2216
2218
2219 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2220
2221 switch( type )
2222 {
2223 case 0x0d07: /* Unknown */
2224 case 0x0e07: /* Unknown */
2225 default: return lex_Generic;
2226 case 0x0001:
2227 case 0x0002:
2228 case 0x0011:
2229 case 0x0012:
2230 case 0x0013:
2231 case 0x0014: return lex_Modifier;
2232 case 0x0003:
2233 case 0x0009:
2234 case 0x000a:
2235 case 0x000b:
2236 case 0x000d:
2237 case 0x000e:
2238 case 0x000f:
2239 case 0x0010: return lex_Consonant;
2240 case 0x0004: return lex_Nukta;
2241 case 0x0005: return lex_Halant;
2242 case 0x0006:
2243 case 0x0008: return lex_Vowel;
2244 case 0x0007:
2245 case 0x0107: return lex_Matra_post;
2246 case 0x0207:
2247 case 0x0307: return lex_Matra_pre;
2248 case 0x0807:
2249 case 0x0907:
2250 case 0x0a07:
2251 case 0x0b07:
2252 case 0x0c07:
2253 case 0x0407: return lex_Composed_Vowel;
2254 case 0x0507: return lex_Matra_above;
2255 case 0x0607: return lex_Matra_below;
2256 case 0x000c:
2257 case 0x0015: return lex_Ra;
2258 };
2259}
2260
2262{
2263 switch (c)
2264 {
2265 case 0x0DDA:
2266 case 0x0DDD:
2267 case 0x0DDC:
2268 case 0x0DDE: return lex_Matra_post;
2269 default:
2270 return unicode_lex(c);
2271 }
2272}
2273
2275 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2276 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2277 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2278 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2279 {0x0000, {0x0000,0x0000,0x0}}};
2280
2282{
2283 int cCount = cChars;
2284 int i;
2285 WCHAR *input;
2286 IndicSyllable *syllables = NULL;
2287 int syllable_count = 0;
2288
2289 if (*pcGlyphs != cChars)
2290 {
2291 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2292 return;
2293 }
2294
2295 input = heap_alloc(3 * cChars * sizeof(*input));
2296
2297 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2298
2299 /* Step 1: Decompose multi part vowels */
2301
2302 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2303
2304 /* Step 2: Reorder within Syllables */
2305 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2306 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2307
2308 /* Step 3: Strip dangling joiners */
2309 for (i = 0; i < cCount; i++)
2310 {
2311 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2312 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2313 input[i] = 0x0020;
2314 }
2315
2316 /* Step 4: Base Form application to syllables */
2317 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2318 *pcGlyphs = cCount;
2320
2322 heap_free(syllables);
2323}
2324
2326{
2327 switch (c)
2328 {
2329 case 0x0930: return lex_Ra;
2330 default:
2331 return unicode_lex(c);
2332 }
2333}
2334
2336 {{0x0928, 0x093C, 0x00000}, 0x0929},
2337 {{0x0930, 0x093C, 0x00000}, 0x0931},
2338 {{0x0933, 0x093C, 0x00000}, 0x0934},
2339 {{0x0915, 0x093C, 0x00000}, 0x0958},
2340 {{0x0916, 0x093C, 0x00000}, 0x0959},
2341 {{0x0917, 0x093C, 0x00000}, 0x095A},
2342 {{0x091C, 0x093C, 0x00000}, 0x095B},
2343 {{0x0921, 0x093C, 0x00000}, 0x095C},
2344 {{0x0922, 0x093C, 0x00000}, 0x095D},
2345 {{0x092B, 0x093C, 0x00000}, 0x095E},
2346 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2347
2349{
2350 int cCount = cChars;
2351 WCHAR *input;
2352 IndicSyllable *syllables = NULL;
2353 int syllable_count = 0;
2354 BOOL modern = get_GSUB_Indic2(psa, psc);
2355
2356 if (*pcGlyphs != cChars)
2357 {
2358 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2359 return;
2360 }
2361
2362 input = heap_alloc(cChars * sizeof(*input));
2363 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2364
2365 /* Step 1: Compose Consonant and Nukta */
2367 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2368
2369 /* Step 2: Reorder within Syllables */
2370 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2371 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2372 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2373 *pcGlyphs = cCount;
2374
2375 /* Step 3: Base Form application to syllables */
2376 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2377
2379 heap_free(syllables);
2380}
2381
2383{
2384 switch (c)
2385 {
2386 case 0x09B0: return lex_Ra;
2387 default:
2388 return unicode_lex(c);
2389 }
2390}
2391
2393 {0x09CB, {0x09C7,0x09BE,0x0000}},
2394 {0x09CC, {0x09C7,0x09D7,0x0000}},
2395 {0x0000, {0x0000,0x0000,0x0000}}};
2396
2398 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2399 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2400 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2401 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2402 {{0x0000,0x0000,0x0000}, 0x0000}};
2403
2405{
2406 int cCount = cChars;
2407 WCHAR *input;
2408 IndicSyllable *syllables = NULL;
2409 int syllable_count = 0;
2410 BOOL modern = get_GSUB_Indic2(psa, psc);
2411
2412 if (*pcGlyphs != cChars)
2413 {
2414 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2415 return;
2416 }
2417
2418 input = heap_alloc(2 * cChars * sizeof(*input));
2419 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2420
2421 /* Step 1: Decompose Vowels and Compose Consonants */
2424 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2425
2426 /* Step 2: Reorder within Syllables */
2427 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2428 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2429 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2430 *pcGlyphs = cCount;
2431
2432 /* Step 3: Initial form is only applied to the beginning of words */
2433 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2434 {
2435 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2436 {
2437 int index = cCount;
2438 int gCount = 1;
2439 if (index > 0) index++;
2440
2441 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2442 }
2443 }
2444
2445 /* Step 4: Base Form application to syllables */
2446 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2447
2449 heap_free(syllables);
2450}
2451
2453{
2454 if (c == 0x0A71)
2455 return lex_Modifier;
2456 else
2457 return unicode_lex(c);
2458}
2459
2461 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2462 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2463 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2464 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2465 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2466 {{0x0000,0x0000,0x0000}, 0x0000}};
2467
2469{
2470 int cCount = cChars;
2471 WCHAR *input;
2472 IndicSyllable *syllables = NULL;
2473 int syllable_count = 0;
2474 BOOL modern = get_GSUB_Indic2(psa, psc);
2475
2476 if (*pcGlyphs != cChars)
2477 {
2478 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2479 return;
2480 }
2481
2482 input = heap_alloc(cChars * sizeof(*input));
2483 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2484
2485 /* Step 1: Compose Consonants */
2487 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2488
2489 /* Step 2: Reorder within Syllables */
2490 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2491 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2492 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2493 *pcGlyphs = cCount;
2494
2495 /* Step 3: Base Form application to syllables */
2496 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2497
2499 heap_free(syllables);
2500}
2501
2503{
2504 switch (c)
2505 {
2506 case 0x0AB0: return lex_Ra;
2507 default:
2508 return unicode_lex(c);
2509 }
2510}
2511
2513{
2514 int cCount = cChars;
2515 WCHAR *input;
2516 IndicSyllable *syllables = NULL;
2517 int syllable_count = 0;
2518 BOOL modern = get_GSUB_Indic2(psa, psc);
2519
2520 if (*pcGlyphs != cChars)
2521 {
2522 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2523 return;
2524 }
2525
2526 input = heap_alloc(cChars * sizeof(*input));
2527 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2528
2529 /* Step 1: Reorder within Syllables */
2530 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2531 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2532 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2533 *pcGlyphs = cCount;
2534
2535 /* Step 2: Base Form application to syllables */
2536 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2537
2539 heap_free(syllables);
2540}
2541
2542static int oriya_lex(WCHAR c)
2543{
2544 switch (c)
2545 {
2546 case 0x0B30: return lex_Ra;
2547 default:
2548 return unicode_lex(c);
2549 }
2550}
2551
2553 {0x0B48, {0x0B47,0x0B56,0x0000}},
2554 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2555 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2556 {0x0000, {0x0000,0x0000,0x0000}}};
2557
2559 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2560 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2561 {{0x0000,0x0000,0x0000}, 0x0000}};
2562
2564{
2565 int cCount = cChars;
2566 WCHAR *input;
2567 IndicSyllable *syllables = NULL;
2568 int syllable_count = 0;
2569 BOOL modern = get_GSUB_Indic2(psa, psc);
2570
2571 if (*pcGlyphs != cChars)
2572 {
2573 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2574 return;
2575 }
2576
2577 input = heap_alloc(2 * cChars * sizeof(*input));
2578 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2579
2580 /* Step 1: Decompose Vowels and Compose Consonants */
2583 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2584
2585 /* Step 2: Reorder within Syllables */
2586 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2587 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2588 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2589 *pcGlyphs = cCount;
2590
2591 /* Step 3: Base Form application to syllables */
2592 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2593
2595 heap_free(syllables);
2596}
2597
2598static int tamil_lex(WCHAR c)
2599{
2600 return unicode_lex(c);
2601}
2602
2604 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2605 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2606 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2607 {0x0000, {0x0000,0x0000,0x0000}}};
2608
2610 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2611 {{0x0000,0x0000,0x0000}, 0x0000}};
2612
2614{
2615 int cCount = cChars;
2616 WCHAR *input;
2617 IndicSyllable *syllables = NULL;
2618 int syllable_count = 0;
2619 BOOL modern = get_GSUB_Indic2(psa, psc);
2620
2621 if (*pcGlyphs != cChars)
2622 {
2623 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2624 return;
2625 }
2626
2627 input = heap_alloc(2 * cChars * sizeof(*input));
2628 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2629
2630 /* Step 1: Decompose Vowels and Compose Consonants */
2633 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2634
2635 /* Step 2: Reorder within Syllables */
2636 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2637 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2638 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2639 *pcGlyphs = cCount;
2640
2641 /* Step 3: Base Form application to syllables */
2643
2645 heap_free(syllables);
2646}
2647
2648static int telugu_lex(WCHAR c)
2649{
2650 switch (c)
2651 {
2652 case 0x0C43:
2653 case 0x0C44: return lex_Modifier;
2654 default:
2655 return unicode_lex(c);
2656 }
2657}
2658
2660 {0x0C48, {0x0C46,0x0C56,0x0000}},
2661 {0x0000, {0x0000,0x0000,0x0000}}};
2662
2664{
2665 int cCount = cChars;
2666 WCHAR *input;
2667 IndicSyllable *syllables = NULL;
2668 int syllable_count = 0;
2669 BOOL modern = get_GSUB_Indic2(psa, psc);
2670
2671 if (*pcGlyphs != cChars)
2672 {
2673 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2674 return;
2675 }
2676
2677 input = heap_alloc(2 * cChars * sizeof(*input));
2678 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2679
2680 /* Step 1: Decompose Vowels */
2682 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2683
2684 /* Step 2: Reorder within Syllables */
2685 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2686 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2687 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2688 *pcGlyphs = cCount;
2689
2690 /* Step 3: Base Form application to syllables */
2692
2694 heap_free(syllables);
2695}
2696
2698{
2699 switch (c)
2700 {
2701 case 0x0CB0: return lex_Ra;
2702 default:
2703 return unicode_lex(c);
2704 }
2705}
2706
2708 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2709 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2710 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2711 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2712 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2713 {0x0000, {0x0000,0x0000,0x0000}}};
2714
2716{
2717 int cCount = cChars;
2718 WCHAR *input;
2719 IndicSyllable *syllables = NULL;
2720 int syllable_count = 0;
2721 BOOL modern = get_GSUB_Indic2(psa, psc);
2722
2723 if (*pcGlyphs != cChars)
2724 {
2725 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2726 return;
2727 }
2728
2729 input = heap_alloc(3 * cChars * sizeof(*input));
2730 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2731
2732 /* Step 1: Decompose Vowels */
2734 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2735
2736 /* Step 2: Reorder within Syllables */
2737 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2738 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2739 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2740 *pcGlyphs = cCount;
2741
2742 /* Step 3: Base Form application to syllables */
2744
2746 heap_free(syllables);
2747}
2748
2750{
2751 return unicode_lex(c);
2752}
2753
2755 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2756 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2757 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2758 {0x0000, {0x0000,0x0000,0x0000}}};
2759
2761{
2762 int cCount = cChars;
2763 WCHAR *input;
2764 IndicSyllable *syllables = NULL;
2765 int syllable_count = 0;
2766 BOOL modern = get_GSUB_Indic2(psa, psc);
2767
2768 if (*pcGlyphs != cChars)
2769 {
2770 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2771 return;
2772 }
2773
2774 input = heap_alloc(2 * cChars * sizeof(*input));
2775 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2776
2777 /* Step 1: Decompose Vowels */
2779 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2780
2781 /* Step 2: Reorder within Syllables */
2782 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2783 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2784 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2785 *pcGlyphs = cCount;
2786
2787 /* Step 3: Base Form application to syllables */
2789
2791 heap_free(syllables);
2792}
2793
2794static int khmer_lex(WCHAR c)
2795{
2796 return unicode_lex(c);
2797}
2798
2800{
2801 int cCount = cChars;
2802 WCHAR *input;
2803 IndicSyllable *syllables = NULL;
2804 int syllable_count = 0;
2805
2806 if (*pcGlyphs != cChars)
2807 {
2808 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2809 return;
2810 }
2811
2812 input = heap_alloc(cChars * sizeof(*input));
2813 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2814
2815 /* Step 1: Reorder within Syllables */
2816 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2817 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2818 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2819 *pcGlyphs = cCount;
2820
2821 /* Step 2: Base Form application to syllables */
2823
2825 heap_free(syllables);
2826}
2827
2829{
2830 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2831}
2832
2834{
2835 INT *context_shape;
2836 INT dirL;
2837 int i;
2838 int char_index;
2839 int glyph_index;
2840
2841 if (*pcGlyphs != cChars)
2842 {
2843 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2844 return;
2845 }
2846
2847 if (!psa->fLogicalOrder && psa->fRTL)
2848 dirL = -1;
2849 else
2850 dirL = 1;
2851
2852 if (!psc->GSUB_Table)
2853 return;
2854
2855 context_shape = heap_alloc(cChars * sizeof(*context_shape));
2856
2857 for (i = 0; i < cChars; i++)
2858 {
2859 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2860 {
2861 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2862 context_shape[i] = Xn;
2863 else
2864 context_shape[i] = Xl;
2865 }
2866 else
2867 {
2868 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2869 context_shape[i] = Xr;
2870 else
2871 context_shape[i] = Xm;
2872 }
2873 }
2874
2875 /* Contextual Shaping */
2876 if (dirL > 0)
2877 char_index = glyph_index = 0;
2878 else
2879 char_index = glyph_index = cChars-1;
2880
2881 while(char_index < cChars && char_index >= 0)
2882 {
2883 INT nextIndex;
2884 INT prevCount = *pcGlyphs;
2885 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
2886
2887 if (nextIndex > GSUB_E_NOGLYPH)
2888 {
2889 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2890 glyph_index = nextIndex;
2891 char_index += dirL;
2892 }
2893 else
2894 {
2895 char_index += dirL;
2896 glyph_index += dirL;
2897 }
2898 }
2899
2900 heap_free(context_shape);
2901}
2902
2903static void ShapeCharGlyphProp_Default( 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)
2904{
2905 int i,k;
2906
2907 for (i = 0; i < cGlyphs; i++)
2908 {
2909 int char_index[20];
2910 int char_count = 0;
2911
2913 if (k>=0)
2914 {
2915 for (; k < cChars && pwLogClust[k] == i; k++)
2916 char_index[char_count++] = k;
2917 }
2918
2919 if (char_count == 0)
2920 continue;
2921
2922 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2923 {
2925 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2926 }
2927 else
2929 }
2930
2933}
2934
2935static void ShapeCharGlyphProp_Latin( 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 )
2936{
2937 int i;
2938
2939 ShapeCharGlyphProp_Default( psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2940
2941 for (i = 0; i < cGlyphs; i++)
2942 if (pGlyphProp[i].sva.fZeroWidth)
2944}
2945
2946static void ShapeCharGlyphProp_Control( 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 )
2947{
2948 int i;
2949 for (i = 0; i < cGlyphs; i++)
2950 {
2951 pGlyphProp[i].sva.fClusterStart = 1;
2952 pGlyphProp[i].sva.fDiacritic = 0;
2954
2955 if (pwGlyphs[i] == psc->sfp.wgDefault)
2956 pGlyphProp[i].sva.fZeroWidth = 0;
2957 else
2958 pGlyphProp[i].sva.fZeroWidth = 1;
2959 }
2960}
2961
2962static 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 )
2963{
2964 int i,k;
2965 int initGlyph, finaGlyph;
2966 INT dirR, dirL;
2967 BYTE *spaces;
2968
2969 spaces = heap_alloc(cGlyphs);
2970 memset(spaces,0,cGlyphs);
2971
2972 if (psa->fLogicalOrder && psa->fRTL)
2973 {
2974 initGlyph = 0;
2975 finaGlyph = cGlyphs-1;
2976 dirR = -1;
2977 dirL = 1;
2978 }
2979 else
2980 {
2981 initGlyph = cGlyphs-1;
2982 finaGlyph = 0;
2983 dirR = 1;
2984 dirL = -1;
2985 }
2986
2987 for (i = 0; i < cGlyphs; i++)
2988 {
2989 for (k = 0; k < cChars; k++)
2990 if (pwLogClust[k] == i)
2991 {
2992 if (pwcChars[k] == 0x0020)
2993 spaces[i] = 1;
2994 }
2995 }
2996
2997 for (i = 0; i < cGlyphs; i++)
2998 {
2999 int char_index[20];
3000 int char_count = 0;
3001 BOOL isInit, isFinal;
3002
3004 if (k>=0)
3005 {
3006 for (; k < cChars && pwLogClust[k] == i; k++)
3007 char_index[char_count++] = k;
3008 }
3009
3010 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3011 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3012
3013 if (char_count == 0)
<