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