1 /*
2 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3 *
4 * This is part of HarfBuzz, an OpenType Layout engine library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 */
24
25 #include "harfbuzz-shaper.h"
26 #include "harfbuzz-shaper-private.h"
27
28 #include <assert.h>
29 #include <stdio.h>
30
31 enum MymrCharClassValues
32 {
33 Mymr_CC_RESERVED = 0,
34 Mymr_CC_CONSONANT = 1, /* Consonant of type 1, that has subscript form */
35 Mymr_CC_CONSONANT2 = 2, /* Consonant of type 2, that has no subscript form */
36 Mymr_CC_NGA = 3, /* Consonant NGA */
37 Mymr_CC_YA = 4, /* Consonant YA */
38 Mymr_CC_RA = 5, /* Consonant RA */
39 Mymr_CC_WA = 6, /* Consonant WA */
40 Mymr_CC_HA = 7, /* Consonant HA */
41 Mymr_CC_IND_VOWEL = 8, /* Independent vowel */
42 Mymr_CC_ZERO_WIDTH_NJ_MARK = 9, /* Zero Width non joiner character (0x200C) */
43 Mymr_CC_VIRAMA = 10, /* Subscript consonant combining character */
44 Mymr_CC_PRE_VOWEL = 11, /* Dependent vowel, prebase (Vowel e) */
45 Mymr_CC_BELOW_VOWEL = 12, /* Dependent vowel, prebase (Vowel u, uu) */
46 Mymr_CC_ABOVE_VOWEL = 13, /* Dependent vowel, prebase (Vowel i, ii, ai) */
47 Mymr_CC_POST_VOWEL = 14, /* Dependent vowel, prebase (Vowel aa) */
48 Mymr_CC_SIGN_ABOVE = 15,
49 Mymr_CC_SIGN_BELOW = 16,
50 Mymr_CC_SIGN_AFTER = 17,
51 Mymr_CC_ZERO_WIDTH_J_MARK = 18, /* Zero width joiner character */
52 Mymr_CC_COUNT = 19 /* This is the number of character classes */
53 };
54
55 enum MymrCharClassFlags
56 {
57 Mymr_CF_CLASS_MASK = 0x0000FFFF,
58
59 Mymr_CF_CONSONANT = 0x01000000, /* flag to speed up comparing */
60 Mymr_CF_MEDIAL = 0x02000000, /* flag to speed up comparing */
61 Mymr_CF_IND_VOWEL = 0x04000000, /* flag to speed up comparing */
62 Mymr_CF_DEP_VOWEL = 0x08000000, /* flag to speed up comparing */
63 Mymr_CF_DOTTED_CIRCLE = 0x10000000, /* add a dotted circle if a character with this flag is the first in a syllable */
64 Mymr_CF_VIRAMA = 0x20000000, /* flag to speed up comparing */
65
66 /* position flags */
67 Mymr_CF_POS_BEFORE = 0x00080000,
68 Mymr_CF_POS_BELOW = 0x00040000,
69 Mymr_CF_POS_ABOVE = 0x00020000,
70 Mymr_CF_POS_AFTER = 0x00010000,
71 Mymr_CF_POS_MASK = 0x000f0000,
72
73 Mymr_CF_AFTER_KINZI = 0x00100000
74 };
75
76 /* Characters that get refrered to by name */
77 enum MymrChar
78 {
79 Mymr_C_SIGN_ZWNJ = 0x200C,
80 Mymr_C_SIGN_ZWJ = 0x200D,
81 Mymr_C_DOTTED_CIRCLE = 0x25CC,
82 Mymr_C_RA = 0x101B,
83 Mymr_C_YA = 0x101A,
84 Mymr_C_NGA = 0x1004,
85 Mymr_C_VOWEL_E = 0x1031,
86 Mymr_C_VIRAMA = 0x1039
87 };
88
89 enum
90 {
91 Mymr_xx = Mymr_CC_RESERVED,
92 Mymr_c1 = Mymr_CC_CONSONANT | Mymr_CF_CONSONANT | Mymr_CF_POS_BELOW,
93 Mymr_c2 = Mymr_CC_CONSONANT2 | Mymr_CF_CONSONANT,
94 Mymr_ng = Mymr_CC_NGA | Mymr_CF_CONSONANT | Mymr_CF_POS_ABOVE,
95 Mymr_ya = Mymr_CC_YA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_AFTER | Mymr_CF_AFTER_KINZI,
96 Mymr_ra = Mymr_CC_RA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BEFORE,
97 Mymr_wa = Mymr_CC_WA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BELOW,
98 Mymr_ha = Mymr_CC_HA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BELOW,
99 Mymr_id = Mymr_CC_IND_VOWEL | Mymr_CF_IND_VOWEL,
100 Mymr_vi = Mymr_CC_VIRAMA | Mymr_CF_VIRAMA | Mymr_CF_POS_ABOVE | Mymr_CF_DOTTED_CIRCLE,
101 Mymr_dl = Mymr_CC_PRE_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_BEFORE | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI,
102 Mymr_db = Mymr_CC_BELOW_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_BELOW | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI,
103 Mymr_da = Mymr_CC_ABOVE_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_ABOVE | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI,
104 Mymr_dr = Mymr_CC_POST_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_AFTER | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI,
105 Mymr_sa = Mymr_CC_SIGN_ABOVE | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_POS_ABOVE | Mymr_CF_AFTER_KINZI,
106 Mymr_sb = Mymr_CC_SIGN_BELOW | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_POS_BELOW | Mymr_CF_AFTER_KINZI,
107 Mymr_sp = Mymr_CC_SIGN_AFTER | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI
108 };
109
110
111 typedef int MymrCharClass;
112
113
114 static const MymrCharClass mymrCharClasses[] =
115 {
116 Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_ng, Mymr_c1, Mymr_c1, Mymr_c1,
117 Mymr_c1, Mymr_c1, Mymr_c2, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, /* 1000 - 100F */
118 Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1,
119 Mymr_c1, Mymr_c1, Mymr_ya, Mymr_ra, Mymr_c1, Mymr_wa, Mymr_c1, Mymr_ha, /* 1010 - 101F */
120 Mymr_c2, Mymr_c2, Mymr_xx, Mymr_id, Mymr_id, Mymr_id, Mymr_id, Mymr_id,
121 Mymr_xx, Mymr_id, Mymr_id, Mymr_xx, Mymr_dr, Mymr_da, Mymr_da, Mymr_db, /* 1020 - 102F */
122 Mymr_db, Mymr_dl, Mymr_da, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_sa, Mymr_sb,
123 Mymr_sp, Mymr_vi, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, /* 1030 - 103F */
124 Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx,
125 Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, /* 1040 - 104F */
126 Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx,
127 Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, /* 1050 - 105F */
128 };
129
130 static MymrCharClass
getMyanmarCharClass(HB_UChar16 ch)131 getMyanmarCharClass (HB_UChar16 ch)
132 {
133 if (ch == Mymr_C_SIGN_ZWJ)
134 return Mymr_CC_ZERO_WIDTH_J_MARK;
135
136 if (ch == Mymr_C_SIGN_ZWNJ)
137 return Mymr_CC_ZERO_WIDTH_NJ_MARK;
138
139 if (ch < 0x1000 || ch > 0x105f)
140 return Mymr_CC_RESERVED;
141
142 return mymrCharClasses[ch - 0x1000];
143 }
144
145 static const signed char mymrStateTable[][Mymr_CC_COUNT] =
146 {
147 /* xx c1, c2 ng ya ra wa ha id zwnj vi dl db da dr sa sb sp zwj */
148 { 1, 4, 4, 2, 4, 4, 4, 4, 24, 1, 27, 17, 18, 19, 20, 21, 1, 1, 4}, /* 0 - ground state */
149 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 1 - exit state (or sp to the right of the syllable) */
150 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 17, 18, 19, 20, 21, -1, -1, 4}, /* 2 - NGA */
151 {-1, 4, 4, 4, 4, 4, 4, 4, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 3 - Virama after NGA */
152 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 17, 18, 19, 20, 21, 1, 1, -1}, /* 4 - Base consonant */
153 {-2, 6, -2, -2, 7, 8, 9, 10, -2, 23, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 5 - First virama */
154 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 25, 17, 18, 19, 20, 21, -1, -1, -1}, /* 6 - c1 after virama */
155 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, -1, -1}, /* 7 - ya after virama */
156 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, -1, -1}, /* 8 - ra after virama */
157 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, -1, -1}, /* 9 - wa after virama */
158 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, 20, 21, -1, -1, -1}, /* 10 - ha after virama */
159 {-1, -1, -1, -1, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 11 - Virama after NGA+zwj */
160 {-2, -2, -2, -2, -2, -2, 13, 14, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 12 - Second virama */
161 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, 17, 18, 19, 20, 21, -1, -1, -1}, /* 13 - wa after virama */
162 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, 20, 21, -1, -1, -1}, /* 14 - ha after virama */
163 {-2, -2, -2, -2, -2, -2, -2, 16, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 15 - Third virama */
164 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, 20, 21, -1, -1, -1}, /* 16 - ha after virama */
165 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, 21, 1, 1, -1}, /* 17 - dl, Dependent vowel e */
166 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, -1, 21, 1, 1, -1}, /* 18 - db, Dependent vowel u,uu */
167 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1}, /* 19 - da, Dependent vowel i,ii,ai */
168 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, 1, 1, -1}, /* 20 - dr, Dependent vowel aa */
169 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1}, /* 21 - sa, Sign anusvara */
170 {-1, -1, -1, -1, -1, -1, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 22 - atha */
171 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1}, /* 23 - zwnj for atha */
172 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1}, /* 24 - Independent vowel */
173 {-2, -2, -2, -2, 26, 26, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 25 - Virama after subscript consonant */
174 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, 1, -1}, /* 26 - ra/ya after subscript consonant + virama */
175 {-1, 6, -1, -1, 7, 8, 9, 10, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 27 - Virama after ground state */
176 /* exit state -2 is for invalid order of medials and combination of invalids
177 with virama where virama should treat as start of next syllable
178 */
179 };
180
181
182
183 /*#define MYANMAR_DEBUG */
184 #ifdef MYANMAR_DEBUG
185 #define MMDEBUG qDebug
186 #else
187 #define MMDEBUG if(0) printf
188 #endif
189
190 /*
191 // Given an input string of characters and a location in which to start looking
192 // calculate, using the state table, which one is the last character of the syllable
193 // that starts in the starting position.
194 */
myanmar_nextSyllableBoundary(const HB_UChar16 * s,int start,int end,HB_Bool * invalid)195 static int myanmar_nextSyllableBoundary(const HB_UChar16 *s, int start, int end, HB_Bool *invalid)
196 {
197 const HB_UChar16 *uc = s + start;
198 int state = 0;
199 int pos = start;
200 *invalid = FALSE;
201
202 while (pos < end) {
203 MymrCharClass charClass = getMyanmarCharClass(*uc);
204 state = mymrStateTable[state][charClass & Mymr_CF_CLASS_MASK];
205 if (pos == start)
206 *invalid = (HB_Bool)(charClass & Mymr_CF_DOTTED_CIRCLE);
207
208 MMDEBUG("state[%d]=%d class=%8x (uc=%4x)", pos - start, state, charClass, *uc);
209
210 if (state < 0) {
211 if (state < -1)
212 --pos;
213 break;
214 }
215 ++uc;
216 ++pos;
217 }
218 return pos;
219 }
220
221 #ifndef NO_OPENTYPE
222 /* ###### might have to change order of above and below forms and substitutions,
223 but according to Unicode below comes before above */
224 static const HB_OpenTypeFeature myanmar_features[] = {
225 { HB_MAKE_TAG('p', 'r', 'e', 'f'), PreFormProperty },
226 { HB_MAKE_TAG('b', 'l', 'w', 'f'), BelowFormProperty },
227 { HB_MAKE_TAG('a', 'b', 'v', 'f'), AboveFormProperty },
228 { HB_MAKE_TAG('p', 's', 't', 'f'), PostFormProperty },
229 { HB_MAKE_TAG('p', 'r', 'e', 's'), PreSubstProperty },
230 { HB_MAKE_TAG('b', 'l', 'w', 's'), BelowSubstProperty },
231 { HB_MAKE_TAG('a', 'b', 'v', 's'), AboveSubstProperty },
232 { HB_MAKE_TAG('p', 's', 't', 's'), PostSubstProperty },
233 { HB_MAKE_TAG('r', 'l', 'i', 'g'), CligProperty }, /* Myanmar1 uses this instead of the other features */
234 { 0, 0 }
235 };
236 #endif
237
238
239 /*
240 // Visual order before shaping should be:
241 //
242 // [Vowel Mark E]
243 // [Virama + Medial Ra]
244 // [Base]
245 // [Virama + Consonant]
246 // [Nga + Virama] (Kinzi) ### should probably come before post forms (medial ya)
247 // [Vowels]
248 // [Marks]
249 //
250 // This means that we can keep the logical order apart from having to
251 // move the pre vowel, medial ra and kinzi
252 */
253
myanmar_shape_syllable(HB_Bool openType,HB_ShaperItem * item,HB_Bool invalid)254 static HB_Bool myanmar_shape_syllable(HB_Bool openType, HB_ShaperItem *item, HB_Bool invalid)
255 {
256 /*
257 // MMDEBUG("\nsyllable from %d len %d, str='%s'", item->item.pos, item->item.length,
258 // item->string->mid(item->from, item->length).toUtf8().data());
259 */
260
261 #ifndef NO_OPENTYPE
262 const int availableGlyphs = item->num_glyphs;
263 #endif
264 const HB_UChar16 *uc = item->string + item->item.pos;
265 int vowel_e = -1;
266 int kinzi = -1;
267 int medial_ra = -1;
268 int base = -1;
269 int i;
270 int len = 0;
271 unsigned short reordered[32];
272 unsigned char properties[32];
273 enum {
274 AboveForm = 0x01,
275 PreForm = 0x02,
276 PostForm = 0x04,
277 BelowForm = 0x08
278 };
279 HB_Bool lastWasVirama = FALSE;
280 int basePos = -1;
281
282 memset(properties, 0, 32*sizeof(unsigned char));
283
284 /* according to the table the max length of a syllable should be around 14 chars */
285 assert(item->item.length < 32);
286
287 #ifdef MYANMAR_DEBUG
288 printf("original:");
289 for (i = 0; i < (int)item->item.length; i++) {
290 printf(" %d: %4x", i, uc[i]);
291 }
292 #endif
293 for (i = 0; i < (int)item->item.length; ++i) {
294 HB_UChar16 chr = uc[i];
295
296 if (chr == Mymr_C_VOWEL_E) {
297 vowel_e = i;
298 continue;
299 }
300 if (i == 0
301 && chr == Mymr_C_NGA
302 && i + 2 < (int)item->item.length
303 && uc[i+1] == Mymr_C_VIRAMA) {
304 int mc = getMyanmarCharClass(uc[i+2]);
305 /*MMDEBUG("maybe kinzi: mc=%x", mc);*/
306 if ((mc & Mymr_CF_CONSONANT) == Mymr_CF_CONSONANT) {
307 kinzi = i;
308 continue;
309 }
310 }
311 if (base >= 0
312 && chr == Mymr_C_VIRAMA
313 && i + 1 < (int)item->item.length
314 && uc[i+1] == Mymr_C_RA) {
315 medial_ra = i;
316 continue;
317 }
318 if (base < 0)
319 base = i;
320 }
321
322 MMDEBUG("\n base=%d, vowel_e=%d, kinzi=%d, medial_ra=%d", base, vowel_e, kinzi, medial_ra);
323 /* write vowel_e if found */
324 if (vowel_e >= 0) {
325 reordered[0] = Mymr_C_VOWEL_E;
326 len = 1;
327 }
328 /* write medial_ra */
329 if (medial_ra >= 0) {
330 reordered[len] = Mymr_C_VIRAMA;
331 reordered[len+1] = Mymr_C_RA;
332 properties[len] = PreForm;
333 properties[len+1] = PreForm;
334 len += 2;
335 }
336
337 /* shall we add a dotted circle?
338 If in the position in which the base should be (first char in the string) there is
339 a character that has the Dotted circle flag (a character that cannot be a base)
340 then write a dotted circle */
341 if (invalid) {
342 reordered[len] = C_DOTTED_CIRCLE;
343 ++len;
344 }
345
346 /* copy the rest of the syllable to the output, inserting the kinzi
347 at the correct place */
348 for (i = 0; i < (int)item->item.length; ++i) {
349 hb_uint16 chr = uc[i];
350 MymrCharClass cc;
351 if (i == vowel_e)
352 continue;
353 if (i == medial_ra || i == kinzi) {
354 ++i;
355 continue;
356 }
357
358 cc = getMyanmarCharClass(uc[i]);
359 if (kinzi >= 0 && i > base && (cc & Mymr_CF_AFTER_KINZI)) {
360 reordered[len] = Mymr_C_NGA;
361 reordered[len+1] = Mymr_C_VIRAMA;
362 properties[len-1] = AboveForm;
363 properties[len] = AboveForm;
364 len += 2;
365 kinzi = -1;
366 }
367
368 if (lastWasVirama) {
369 int prop = 0;
370 switch(cc & Mymr_CF_POS_MASK) {
371 case Mymr_CF_POS_BEFORE:
372 prop = PreForm;
373 break;
374 case Mymr_CF_POS_BELOW:
375 prop = BelowForm;
376 break;
377 case Mymr_CF_POS_ABOVE:
378 prop = AboveForm;
379 break;
380 case Mymr_CF_POS_AFTER:
381 prop = PostForm;
382 break;
383 default:
384 break;
385 }
386 properties[len-1] = prop;
387 properties[len] = prop;
388 if(basePos >= 0 && basePos == len-2)
389 properties[len-2] = prop;
390 }
391 lastWasVirama = (chr == Mymr_C_VIRAMA);
392 if(i == base)
393 basePos = len;
394
395 if ((chr != Mymr_C_SIGN_ZWNJ && chr != Mymr_C_SIGN_ZWJ) || !len) {
396 reordered[len] = chr;
397 ++len;
398 }
399 }
400 if (kinzi >= 0) {
401 reordered[len] = Mymr_C_NGA;
402 reordered[len+1] = Mymr_C_VIRAMA;
403 properties[len] = AboveForm;
404 properties[len+1] = AboveForm;
405 len += 2;
406 }
407
408 if (!item->font->klass->convertStringToGlyphIndices(item->font,
409 reordered, len,
410 item->glyphs, &item->num_glyphs,
411 item->item.bidiLevel % 2))
412 return FALSE;
413
414 MMDEBUG("after shaping: len=%d", len);
415 for (i = 0; i < len; i++) {
416 item->attributes[i].mark = FALSE;
417 item->attributes[i].clusterStart = FALSE;
418 item->attributes[i].justification = 0;
419 item->attributes[i].zeroWidth = FALSE;
420 MMDEBUG(" %d: %4x property=%x", i, reordered[i], properties[i]);
421 }
422
423 /* now we have the syllable in the right order, and can start running it through open type. */
424
425 #ifndef NO_OPENTYPE
426 if (openType) {
427 hb_uint32 where[32];
428
429 for (i = 0; i < len; ++i) {
430 where[i] = ~(PreSubstProperty
431 | BelowSubstProperty
432 | AboveSubstProperty
433 | PostSubstProperty
434 | CligProperty
435 | PositioningProperties);
436 if (properties[i] & PreForm)
437 where[i] &= ~PreFormProperty;
438 if (properties[i] & BelowForm)
439 where[i] &= ~BelowFormProperty;
440 if (properties[i] & AboveForm)
441 where[i] &= ~AboveFormProperty;
442 if (properties[i] & PostForm)
443 where[i] &= ~PostFormProperty;
444 }
445
446 HB_OpenTypeShape(item, where);
447 if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE))
448 return FALSE;
449 } else
450 #endif
451 {
452 MMDEBUG("Not using openType");
453 HB_HeuristicPosition(item);
454 }
455
456 item->attributes[0].clusterStart = TRUE;
457 return TRUE;
458 }
459
HB_MyanmarShape(HB_ShaperItem * item)460 HB_Bool HB_MyanmarShape(HB_ShaperItem *item)
461 {
462 HB_Bool openType = FALSE;
463 unsigned short *logClusters = item->log_clusters;
464
465 HB_ShaperItem syllable = *item;
466 int first_glyph = 0;
467
468 int sstart = item->item.pos;
469 int end = sstart + item->item.length;
470 int i = 0;
471
472 assert(item->item.script == HB_Script_Myanmar);
473 #ifndef NO_OPENTYPE
474 openType = HB_SelectScript(item, myanmar_features);
475 #endif
476
477 MMDEBUG("myanmar_shape: from %d length %d", item->item.pos, item->item.length);
478 while (sstart < end) {
479 HB_Bool invalid;
480 int send = myanmar_nextSyllableBoundary(item->string, sstart, end, &invalid);
481 MMDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart,
482 invalid ? "TRUE" : "FALSE");
483 syllable.item.pos = sstart;
484 syllable.item.length = send-sstart;
485 syllable.glyphs = item->glyphs + first_glyph;
486 syllable.attributes = item->attributes + first_glyph;
487 syllable.advances = item->advances + first_glyph;
488 syllable.offsets = item->offsets + first_glyph;
489 syllable.num_glyphs = item->num_glyphs - first_glyph;
490 if (!myanmar_shape_syllable(openType, &syllable, invalid)) {
491 MMDEBUG("syllable shaping failed, syllable requests %d glyphs", syllable.num_glyphs);
492 item->num_glyphs += syllable.num_glyphs;
493 return FALSE;
494 }
495
496 /* fix logcluster array */
497 MMDEBUG("syllable:");
498 for (i = first_glyph; i < first_glyph + (int)syllable.num_glyphs; ++i)
499 MMDEBUG(" %d -> glyph %x", i, item->glyphs[i]);
500 MMDEBUG(" logclusters:");
501 for (i = sstart; i < send; ++i) {
502 MMDEBUG(" %d -> glyph %d", i, first_glyph);
503 logClusters[i-item->item.pos] = first_glyph;
504 }
505 sstart = send;
506 first_glyph += syllable.num_glyphs;
507 }
508 item->num_glyphs = first_glyph;
509 return TRUE;
510 }
511
HB_MyanmarAttributes(HB_Script script,const HB_UChar16 * text,hb_uint32 from,hb_uint32 len,HB_CharAttributes * attributes)512 void HB_MyanmarAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes)
513 {
514 int end = from + len;
515 const HB_UChar16 *uc = text + from;
516 hb_uint32 i = 0;
517 HB_UNUSED(script);
518 attributes += from;
519 while (i < len) {
520 HB_Bool invalid;
521 hb_uint32 boundary = myanmar_nextSyllableBoundary(text, from+i, end, &invalid) - from;
522
523 attributes[i].charStop = TRUE;
524 if (i)
525 attributes[i-1].lineBreakType = HB_Break;
526
527 if (boundary > len-1)
528 boundary = len;
529 i++;
530 while (i < boundary) {
531 attributes[i].charStop = FALSE;
532 ++uc;
533 ++i;
534 }
535 assert(i == boundary);
536 }
537 }
538
539