OLD | NEW |
| (Empty) |
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 subscrip
t form */ | |
35 Mymr_CC_CONSONANT2 = 2, /* Consonant of type 2, that has no subsc
ript 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 (0x200
C) */ | |
43 Mymr_CC_VIRAMA = 10, /* Subscript consonant combining characte
r */ | |
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 classe
s */ | |
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 w
ith 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_AFTE
R | Mymr_CF_AFTER_KINZI, | |
96 Mymr_ra = Mymr_CC_RA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BEFO
RE, | |
97 Mymr_wa = Mymr_CC_WA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BELO
W, | |
98 Mymr_ha = Mymr_CC_HA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BELO
W, | |
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_DOTT
ED_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 | M
ymr_CF_AFTER_KINZI, | |
106 Mymr_sb = Mymr_CC_SIGN_BELOW | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_POS_BELOW | M
ymr_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, /* 1
000 - 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, /* 1
010 - 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, /* 1
020 - 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, /* 1
030 - 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, /* 1
040 - 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, /* 1
050 - 105F */ | |
128 }; | |
129 | |
130 static MymrCharClass | |
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 syl
lable | |
193 // that starts in the starting position. | |
194 */ | |
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 ins
tead 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 | |
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 c
hars */ | |
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, ki
nzi, 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 if (len > 0) | |
363 properties[len-1] = AboveForm; | |
364 properties[len] = AboveForm; | |
365 len += 2; | |
366 kinzi = -1; | |
367 } | |
368 | |
369 if (lastWasVirama) { | |
370 int prop = 0; | |
371 switch(cc & Mymr_CF_POS_MASK) { | |
372 case Mymr_CF_POS_BEFORE: | |
373 prop = PreForm; | |
374 break; | |
375 case Mymr_CF_POS_BELOW: | |
376 prop = BelowForm; | |
377 break; | |
378 case Mymr_CF_POS_ABOVE: | |
379 prop = AboveForm; | |
380 break; | |
381 case Mymr_CF_POS_AFTER: | |
382 prop = PostForm; | |
383 break; | |
384 default: | |
385 break; | |
386 } | |
387 properties[len-1] = prop; | |
388 properties[len] = prop; | |
389 if(basePos >= 0 && basePos == len-2) | |
390 properties[len-2] = prop; | |
391 } | |
392 lastWasVirama = (chr == Mymr_C_VIRAMA); | |
393 if(i == base) | |
394 basePos = len; | |
395 | |
396 if ((chr != Mymr_C_SIGN_ZWNJ && chr != Mymr_C_SIGN_ZWJ) || !len) { | |
397 reordered[len] = chr; | |
398 ++len; | |
399 } | |
400 } | |
401 if (kinzi >= 0) { | |
402 reordered[len] = Mymr_C_NGA; | |
403 reordered[len+1] = Mymr_C_VIRAMA; | |
404 properties[len] = AboveForm; | |
405 properties[len+1] = AboveForm; | |
406 len += 2; | |
407 } | |
408 | |
409 if (!item->font->klass->convertStringToGlyphIndices(item->font, | |
410 reordered, len, | |
411 item->glyphs, &item->num
_glyphs, | |
412 item->item.bidiLevel % 2
)) | |
413 return FALSE; | |
414 | |
415 MMDEBUG("after shaping: len=%d", len); | |
416 for (i = 0; i < len; i++) { | |
417 item->attributes[i].mark = FALSE; | |
418 item->attributes[i].clusterStart = FALSE; | |
419 item->attributes[i].justification = 0; | |
420 item->attributes[i].zeroWidth = FALSE; | |
421 MMDEBUG(" %d: %4x property=%x", i, reordered[i], properties[i]); | |
422 } | |
423 | |
424 /* now we have the syllable in the right order, and can start running it thr
ough open type. */ | |
425 | |
426 #ifndef NO_OPENTYPE | |
427 if (openType) { | |
428 hb_uint32 where[32]; | |
429 | |
430 for (i = 0; i < len; ++i) { | |
431 where[i] = ~(PreSubstProperty | |
432 | BelowSubstProperty | |
433 | AboveSubstProperty | |
434 | PostSubstProperty | |
435 | CligProperty | |
436 | PositioningProperties); | |
437 if (properties[i] & PreForm) | |
438 where[i] &= ~PreFormProperty; | |
439 if (properties[i] & BelowForm) | |
440 where[i] &= ~BelowFormProperty; | |
441 if (properties[i] & AboveForm) | |
442 where[i] &= ~AboveFormProperty; | |
443 if (properties[i] & PostForm) | |
444 where[i] &= ~PostFormProperty; | |
445 } | |
446 | |
447 HB_OpenTypeShape(item, where); | |
448 if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE)) | |
449 return FALSE; | |
450 } else | |
451 #endif | |
452 { | |
453 MMDEBUG("Not using openType"); | |
454 HB_HeuristicPosition(item); | |
455 } | |
456 | |
457 item->attributes[0].clusterStart = TRUE; | |
458 return TRUE; | |
459 } | |
460 | |
461 HB_Bool HB_MyanmarShape(HB_ShaperItem *item) | |
462 { | |
463 HB_Bool openType = FALSE; | |
464 unsigned short *logClusters = item->log_clusters; | |
465 | |
466 HB_ShaperItem syllable = *item; | |
467 int first_glyph = 0; | |
468 | |
469 int sstart = item->item.pos; | |
470 int end = sstart + item->item.length; | |
471 int i = 0; | |
472 | |
473 assert(item->item.script == HB_Script_Myanmar); | |
474 #ifndef NO_OPENTYPE | |
475 openType = HB_SelectScript(item, myanmar_features); | |
476 #endif | |
477 | |
478 MMDEBUG("myanmar_shape: from %d length %d", item->item.pos, item->item.lengt
h); | |
479 while (sstart < end) { | |
480 HB_Bool invalid; | |
481 int send = myanmar_nextSyllableBoundary(item->string, sstart, end, &inva
lid); | |
482 MMDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart, | |
483 invalid ? "TRUE" : "FALSE"); | |
484 syllable.item.pos = sstart; | |
485 syllable.item.length = send-sstart; | |
486 syllable.glyphs = item->glyphs + first_glyph; | |
487 syllable.attributes = item->attributes + first_glyph; | |
488 syllable.advances = item->advances + first_glyph; | |
489 syllable.offsets = item->offsets + first_glyph; | |
490 syllable.num_glyphs = item->num_glyphs - first_glyph; | |
491 if (!myanmar_shape_syllable(openType, &syllable, invalid)) { | |
492 MMDEBUG("syllable shaping failed, syllable requests %d glyphs", syll
able.num_glyphs); | |
493 item->num_glyphs += syllable.num_glyphs; | |
494 return FALSE; | |
495 } | |
496 | |
497 /* fix logcluster array */ | |
498 MMDEBUG("syllable:"); | |
499 for (i = first_glyph; i < first_glyph + (int)syllable.num_glyphs; ++i) | |
500 MMDEBUG(" %d -> glyph %x", i, item->glyphs[i]); | |
501 MMDEBUG(" logclusters:"); | |
502 for (i = sstart; i < send; ++i) { | |
503 MMDEBUG(" %d -> glyph %d", i, first_glyph); | |
504 logClusters[i-item->item.pos] = first_glyph; | |
505 } | |
506 sstart = send; | |
507 first_glyph += syllable.num_glyphs; | |
508 } | |
509 item->num_glyphs = first_glyph; | |
510 return TRUE; | |
511 } | |
512 | |
513 void HB_MyanmarAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 fr
om, hb_uint32 len, HB_CharAttributes *attributes) | |
514 { | |
515 int end = from + len; | |
516 const HB_UChar16 *uc = text + from; | |
517 hb_uint32 i = 0; | |
518 HB_UNUSED(script); | |
519 attributes += from; | |
520 while (i < len) { | |
521 HB_Bool invalid; | |
522 hb_uint32 boundary = myanmar_nextSyllableBoundary(text, from+i, end, &in
valid) - from; | |
523 | |
524 attributes[i].charStop = TRUE; | |
525 if (i) | |
526 attributes[i-1].lineBreakType = HB_Break; | |
527 | |
528 if (boundary > len-1) | |
529 boundary = len; | |
530 i++; | |
531 while (i < boundary) { | |
532 attributes[i].charStop = FALSE; | |
533 ++uc; | |
534 ++i; | |
535 } | |
536 assert(i == boundary); | |
537 } | |
538 } | |
539 | |
OLD | NEW |