ReactOS  0.4.13-dev-73-gcfe54aa
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 
68 static 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);
69 static 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 );
70 static 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 );
71 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 );
72 static 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
78 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 );
79 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 );
80 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 );
81 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 );
82 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 );
83 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 );
84 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 );
85 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 );
86 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
87 
88 extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
89 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
90 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
91 
93  jtU,
94  jtT,
95  jtR,
96  jtL,
97  jtD,
99 };
100 
102  Xn=0,
103  Xr,
104  Xl,
105  Xm,
106  /* Syriac Alaph */
110 };
111 
112 typedef struct tagVowelComponents
113 {
117 
119 {
123 
124 typedef 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 */
130 static 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 
173 static 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 
210 static 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 
268 static const char *const required_lao_features[] =
269 {
270  "ccmp",
271  NULL
272 };
273 
274 static 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 
314 static 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 
331 static 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 
350 static 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 
367 static 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 
383 static 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 
410 static 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 
448 typedef struct ScriptShapeDataTag {
451  const char *const *requiredFeatures;
456 
457 /* in order of scripts */
458 static const ScriptShapeData ShapingData[] =
459 {
460  {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
472  {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
473  {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
474  {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
475  {{ standard_features, 2}, {latin_gpos_features, 3}, 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 {
574  UINT charset;
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 
616 static 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 
654 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)
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 
730  heap_free(glyphs);
731  return rc;
732 }
733 
734 static 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)
751  pwLogClust[j] = pwLogClust[k];
752  }
753  }
754  }
755  }
756 }
757 
758 static 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 
823 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 )
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 
864 static void GPOS_apply_feature(const ScriptCache *psc, const OUTLINETEXTMETRICW *otm,
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 
893 static 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 
952 static 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 
964 static 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 
989 static inline BOOL right_join_causing(CHAR joining_type)
990 {
991  return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
992 }
993 
994 static inline BOOL left_join_causing(CHAR joining_type)
995 {
996  return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
997 }
998 
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 
1651 static 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 
1671 static 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 
1693 static 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 
1846 static void SecondReorder_Blwf_follows_matra(const WCHAR *chars, const IndicSyllable *s,
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 
1872 static void SecondReorder_Matra_precede_base(const WCHAR *chars, const IndicSyllable *s,
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 
1950 static 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 
1961 static 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 
1974 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
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 
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 
2016 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
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 
2068 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
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 
2081 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)
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 
2126 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)
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 
2208 static 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 
2261 static int sinhala_lex(WCHAR c)
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;
2319  ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2320 
2321  heap_free(input);
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 
2378  heap_free(input);
2379  heap_free(syllables);
2380 }
2381 
2382 static int bengali_lex(WCHAR c)
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 
2448  heap_free(input);
2449  heap_free(syllables);
2450 }
2451 
2452 static int gurmukhi_lex(WCHAR c)
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 
2498  heap_free(input);
2499  heap_free(syllables);
2500 }
2501 
2502 static int gujarati_lex(WCHAR c)
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 
2538  heap_free(input);
2539  heap_free(syllables);
2540 }
2541 
2542 static 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 
2552 static const VowelComponents Oriya_vowels[] = {
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 
2594  heap_free(input);
2595  heap_free(syllables);
2596 }
2597 
2598 static int tamil_lex(WCHAR c)
2599 {
2600  return unicode_lex(c);
2601 }
2602 
2603 static const VowelComponents Tamil_vowels[] = {
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 
2644  heap_free(input);
2645  heap_free(syllables);
2646 }
2647 
2648 static 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 
2659 static const VowelComponents Telugu_vowels[] = {
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 
2693  heap_free(input);
2694  heap_free(syllables);
2695 }
2696 
2697 static int kannada_lex(WCHAR c)
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 
2745  heap_free(input);
2746  heap_free(syllables);
2747 }
2748 
2749 static int malayalam_lex(WCHAR c)
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 
2790  heap_free(input);
2791  heap_free(syllables);
2792 }
2793 
2794 static 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 */
2822  ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2823 
2824  heap_free(input);
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 
2903 static 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  {
2924  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2925  pCharProp[char_index[0]].fCanGlyphAlone = 1;
2926  }
2927  else
2929  }
2930 
2931  OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2933 }
2934 
2935 static 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)
2943  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2944 }
2945 
2946 static 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;
2953  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
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 
2962 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 )
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)
3014  continue;
3015 
3016  if (char_count == 1)
3017  {
3018  if (pwcChars[char_index[0]] == 0x0020) /* space */
3019  {
3021  pCharProp[char_index[0]].fCanGlyphAlone = 1;
3022  }
3023  else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3025  else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3026  {
3027  if (!isInit && !isFinal)
3029  else if (isInit)
3031  else
3032  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3033  }
3034  else if (!isInit)
3035  {
3036  if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3038  else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3040  else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3042  else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3043  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3044  else
3045  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3046  }
3047  else if (!isInit && !isFinal)
3049  else
3050  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3051  }
3052  else if (char_count == 2)
3053  {
3054  if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3056  else if (!isInit)
3058  else
3059  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3060  }
3061  else if (!isInit && !isFinal)
3063  else
3064  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3065  }
3066 
3067  OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3069  heap_free(spaces);
3070 }
3071 
3072 static 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 )
3073 {
3074  int i,k;
3075 
3076  for (i = 0; i < cGlyphs; i++)
3077  {
3078  int char_index[20];
3079  int char_count = 0;
3080 
3082  if (k>=0)
3083  {
3084  for (; k < cChars && pwLogClust[k] == i; k++)
3085  char_index[char_count++] = k;
3086  }
3087 
3088  if (char_count == 0)
3089  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3090  else
3091  {
3093  if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3094  pCharProp[char_index[0]].fCanGlyphAlone = 1;
3095  }
3096  }
3097 
3098  OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3100 }
3101 
3102 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 )
3103 {
3104  int i;
3105  int finaGlyph;
3106  INT dirL;
3107 
3108  if (!psa->fLogicalOrder && psa->fRTL)
3109  {
3110  finaGlyph = 0;
3111  dirL = -1;
3112  }
3113  else
3114  {
3115  finaGlyph = cGlyphs-1;
3116  dirL = 1;
3117  }
3118 
3119  OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3120 
3121  for (i = 0; i < cGlyphs; i++)
3122  {
3123  int k;
3124  int char_index[20];
3125  int char_count = 0;
3126 
3128  if (k>=0)
3129  {
3130  for (; k < cChars && pwLogClust[k] == i; k++)
3131  char_index[char_count++] = k;
3132  }
3133 
3134  if (i == finaGlyph)
3135  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3136  else
3138 
3139  if (char_count == 0)
3140  continue;
3141 
3142  if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3143  pCharProp[char_index[0]].fCanGlyphAlone = 1;
3144 
3145  /* handle Thai SARA AM (U+0E33) differently than GDEF */
3146  if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3147  pGlyphProp[i].sva.fClusterStart = 0;
3148  }
3149 
3151 
3152  /* Do not allow justification between marks and their base */
3153  for (i = 0; i < cGlyphs; i++)
3154  {
3155  if (!pGlyphProp[i].sva.fClusterStart)
3156  pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3157  }
3158 }
3159 
3160 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)
3161 {
3162  int i,k;
3163 
3164  for (i = 0; i < cGlyphs; i++)
3165  {
3166  int char_index[20];
3167  int char_count = 0;
3168 
3170  if (k>=0)
3171  {
3172  for (; k < cChars && pwLogClust[k] == i; k++)
3173  char_index[char_count++] = k;
3174  }
3175 
3176  if (char_count == 0)
3177  continue;
3178 
3179  if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3180  {
3182  pCharProp[char_index[0]].fCanGlyphAlone = 1;
3183  }
3184  else
3185  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3186  }
3187  OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3189 }
3190 
3191 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)
3192 {
3193  int i,k;
3194 
3195  for (i = 0; i < cGlyphs; i++)
3196  {
3197  int char_index[20];
3198  int char_count = 0;
3199 
3201  if (k>=0)
3202  {
3203  for (; k < cChars && pwLogClust[k] == i; k++)
3204  char_index[char_count++] = k;
3205  }
3206 
3207  if (char_count == 0)
3208  continue;
3209 
3210  if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3211  {
3212  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3213  pCharProp[char_index[0]].fCanGlyphAlone = 1;
3214  }
3215  else
3216  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3217  }
3218  OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3220 
3221  /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3222  for (i = 0; i < cGlyphs; i++)
3223  {
3224  if (!pGlyphProp[i].sva.fClusterStart)
3225  {
3226  pGlyphProp[i].sva.fDiacritic = 0;
3227  pGlyphProp[i].sva.fZeroWidth = 0;
3228  }
3229  }
3230 }
3231 
3232 static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables, BOOL override_gsub)
3233 {
3234  int i,k;
3235 
3236  OpenType_GDEF_UpdateGlyphProps(psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3237  for (i = 0; i < cGlyphs; i++)
3238  {
3239  int char_index[20];
3240  int char_count = 0;
3241 
3243  if (k>=0)
3244  {
3245  for (; k < cChars && pwLogClust[k] == i; k++)
3246  char_index[char_count++] = k;
3247  }
3248 
3249  if (override_gsub)
3250  {
3251  /* Most indic scripts do not set fDiacritic or fZeroWidth */
3252  pGlyphProp[i].sva.fDiacritic = FALSE;
3253  pGlyphProp[i].sva.fZeroWidth = FALSE;
3254  }
3255 
3256  if (char_count == 0)
3257  {
3258  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3259  continue;
3260  }
3261 
3262  if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3263  {
3264  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3265  pCharProp[char_index[0]].fCanGlyphAlone = 1;
3266  }
3267  else
3268  pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3269 
3270  pGlyphProp[i].sva.fClusterStart = 0;
3271  for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3272  switch (lexical(pwcChars[char_index[k]]))
3273  {
3274  case lex_Matra_pre:
3275  case lex_Matra_post:
3276  case lex_Matra_above:
3277  case lex_Matra_below:
3278  case lex_Modifier:
3279  case lex_Halant:
3280  break;
3281  case lex_ZWJ:
3282  case lex_ZWNJ:
3283  /* check for dangling joiners */
3284  if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3285  pGlyphProp[i].sva.fClusterStart = 1;
3286  else
3287  k = char_count;
3288  break;
3289  default:
3290  pGlyphProp[i].sva.fClusterStart = 1;
3291  break;