OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2010 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 #include <assert.h> | |
28 | |
29 #ifndef NO_OPENTYPE | |
30 static const HB_OpenTypeFeature greek_features[] = { | |
31 { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty }, | |
32 { HB_MAKE_TAG('l', 'i', 'g', 'a'), CcmpProperty }, | |
33 { HB_MAKE_TAG('c', 'l', 'i', 'g'), CcmpProperty }, | |
34 {0, 0} | |
35 }; | |
36 #endif | |
37 | |
38 /* | |
39 Greek decompositions | |
40 */ | |
41 | |
42 | |
43 typedef struct _hb_greek_decomposition { | |
44 HB_UChar16 composed; | |
45 HB_UChar16 base; | |
46 } hb_greek_decomposition; | |
47 | |
48 static const hb_greek_decomposition decompose_0x300[] = { | |
49 { 0x1FBA, 0x0391 }, | |
50 { 0x1FC8, 0x0395 }, | |
51 { 0x1FCA, 0x0397 }, | |
52 { 0x1FDA, 0x0399 }, | |
53 { 0x1FF8, 0x039F }, | |
54 { 0x1FEA, 0x03A5 }, | |
55 { 0x1FFA, 0x03A9 }, | |
56 { 0x1F70, 0x03B1 }, | |
57 { 0x1F72, 0x03B5 }, | |
58 { 0x1F74, 0x03B7 }, | |
59 { 0x1F76, 0x03B9 }, | |
60 { 0x1F78, 0x03BF }, | |
61 { 0x1F7A, 0x03C5 }, | |
62 { 0x1F7C, 0x03C9 }, | |
63 { 0x1FD2, 0x03CA }, | |
64 { 0x1FE2, 0x03CB }, | |
65 { 0x1F02, 0x1F00 }, | |
66 { 0, 0 } | |
67 }; | |
68 | |
69 static HB_UChar16 compose_0x300(HB_UChar16 base) | |
70 { | |
71 if ((base ^ 0x1f00) < 0x100) { | |
72 if (base <= 0x1f69 && !(base & 0x6)) | |
73 return base + 2; | |
74 if (base == 0x1fbf) | |
75 return 0x1fcd; | |
76 if (base == 0x1ffe) | |
77 return 0x1fdd; | |
78 return 0; | |
79 } | |
80 { | |
81 const hb_greek_decomposition *d = decompose_0x300; | |
82 while (d->base && d->base != base) | |
83 ++d; | |
84 return d->composed; | |
85 } | |
86 } | |
87 | |
88 static const hb_greek_decomposition decompose_0x301[] = { | |
89 { 0x0386, 0x0391 }, | |
90 { 0x0388, 0x0395 }, | |
91 { 0x0389, 0x0397 }, | |
92 { 0x038A, 0x0399 }, | |
93 { 0x038C, 0x039F }, | |
94 { 0x038E, 0x03A5 }, | |
95 { 0x038F, 0x03A9 }, | |
96 { 0x03AC, 0x03B1 }, | |
97 { 0x03AD, 0x03B5 }, | |
98 { 0x03AE, 0x03B7 }, | |
99 { 0x03AF, 0x03B9 }, | |
100 { 0x03CC, 0x03BF }, | |
101 { 0x03CD, 0x03C5 }, | |
102 { 0x03CE, 0x03C9 }, | |
103 { 0x0390, 0x03CA }, | |
104 { 0x03B0, 0x03CB }, | |
105 { 0x03D3, 0x03D2 }, | |
106 { 0, 0 } | |
107 }; | |
108 | |
109 | |
110 static HB_UChar16 compose_0x301(HB_UChar16 base) | |
111 { | |
112 if ((base ^ 0x1f00) < 0x100) { | |
113 if (base <= 0x1f69 && !(base & 0x6)) | |
114 return base + 4; | |
115 if (base == 0x1fbf) | |
116 return 0x1fce; | |
117 if (base == 0x1ffe) | |
118 return 0x1fde; | |
119 } | |
120 { | |
121 const hb_greek_decomposition *d = decompose_0x301; | |
122 while (d->base && d->base != base) | |
123 ++d; | |
124 return d->composed; | |
125 } | |
126 } | |
127 | |
128 static const hb_greek_decomposition decompose_0x304[] = { | |
129 { 0x1FB9, 0x0391 }, | |
130 { 0x1FD9, 0x0399 }, | |
131 { 0x1FE9, 0x03A5 }, | |
132 { 0x1FB1, 0x03B1 }, | |
133 { 0x1FD1, 0x03B9 }, | |
134 { 0x1FE1, 0x03C5 }, | |
135 { 0, 0 } | |
136 }; | |
137 | |
138 static HB_UChar16 compose_0x304(HB_UChar16 base) | |
139 { | |
140 const hb_greek_decomposition *d = decompose_0x304; | |
141 while (d->base && d->base != base) | |
142 ++d; | |
143 return d->composed; | |
144 } | |
145 | |
146 static const hb_greek_decomposition decompose_0x306[] = { | |
147 { 0x1FB8, 0x0391 }, | |
148 { 0x1FD8, 0x0399 }, | |
149 { 0x1FE8, 0x03A5 }, | |
150 { 0x1FB0, 0x03B1 }, | |
151 { 0x1FD0, 0x03B9 }, | |
152 { 0x1FE0, 0x03C5 }, | |
153 { 0, 0 } | |
154 }; | |
155 | |
156 static HB_UChar16 compose_0x306(HB_UChar16 base) | |
157 { | |
158 const hb_greek_decomposition *d = decompose_0x306; | |
159 while (d->base && d->base != base) | |
160 ++d; | |
161 return d->composed; | |
162 } | |
163 | |
164 static const hb_greek_decomposition decompose_0x308[] = { | |
165 { 0x03AA, 0x0399 }, | |
166 { 0x03AB, 0x03A5 }, | |
167 { 0x03CA, 0x03B9 }, | |
168 { 0x03CB, 0x03C5 }, | |
169 { 0x03D4, 0x03D2 }, | |
170 { 0, 0 } | |
171 }; | |
172 | |
173 static HB_UChar16 compose_0x308(HB_UChar16 base) | |
174 { | |
175 const hb_greek_decomposition *d = decompose_0x308; | |
176 while (d->base && d->base != base) | |
177 ++d; | |
178 return d->composed; | |
179 } | |
180 | |
181 | |
182 static const hb_greek_decomposition decompose_0x313[] = { | |
183 { 0x1F08, 0x0391 }, | |
184 { 0x1F18, 0x0395 }, | |
185 { 0x1F28, 0x0397 }, | |
186 { 0x1F38, 0x0399 }, | |
187 { 0x1F48, 0x039F }, | |
188 { 0x1F68, 0x03A9 }, | |
189 { 0x1F00, 0x03B1 }, | |
190 { 0x1F10, 0x03B5 }, | |
191 { 0x1F20, 0x03B7 }, | |
192 { 0x1F30, 0x03B9 }, | |
193 { 0x1F40, 0x03BF }, | |
194 { 0x1FE4, 0x03C1 }, | |
195 { 0x1F50, 0x03C5 }, | |
196 { 0x1F60, 0x03C9 }, | |
197 { 0, 0 } | |
198 }; | |
199 | |
200 static HB_UChar16 compose_0x313(HB_UChar16 base) | |
201 { | |
202 const hb_greek_decomposition *d = decompose_0x313; | |
203 while (d->base && d->base != base) | |
204 ++d; | |
205 return d->composed; | |
206 } | |
207 | |
208 static const hb_greek_decomposition decompose_0x314[] = { | |
209 { 0x1F09, 0x0391 }, | |
210 { 0x1F19, 0x0395 }, | |
211 { 0x1F29, 0x0397 }, | |
212 { 0x1F39, 0x0399 }, | |
213 { 0x1F49, 0x039F }, | |
214 { 0x1FEC, 0x03A1 }, | |
215 { 0x1F59, 0x03A5 }, | |
216 { 0x1F69, 0x03A9 }, | |
217 { 0x1F01, 0x03B1 }, | |
218 { 0x1F11, 0x03B5 }, | |
219 { 0x1F21, 0x03B7 }, | |
220 { 0x1F31, 0x03B9 }, | |
221 { 0x1F41, 0x03BF }, | |
222 { 0x1FE5, 0x03C1 }, | |
223 { 0x1F51, 0x03C5 }, | |
224 { 0x1F61, 0x03C9 }, | |
225 { 0, 0 } | |
226 }; | |
227 | |
228 static HB_UChar16 compose_0x314(HB_UChar16 base) | |
229 { | |
230 const hb_greek_decomposition *d = decompose_0x314; | |
231 while (d->base && d->base != base) | |
232 ++d; | |
233 return d->composed; | |
234 } | |
235 | |
236 static const hb_greek_decomposition decompose_0x342[] = { | |
237 { 0x1FB6, 0x03B1 }, | |
238 { 0x1FC6, 0x03B7 }, | |
239 { 0x1FD6, 0x03B9 }, | |
240 { 0x1FE6, 0x03C5 }, | |
241 { 0x1FF6, 0x03C9 }, | |
242 { 0x1FD7, 0x03CA }, | |
243 { 0x1FE7, 0x03CB }, | |
244 { 0x1F06, 0x1F00 }, | |
245 { 0x1F07, 0x1F01 }, | |
246 { 0x1F0E, 0x1F08 }, | |
247 { 0x1F0F, 0x1F09 }, | |
248 { 0x1F26, 0x1F20 }, | |
249 { 0x1F27, 0x1F21 }, | |
250 { 0x1F2E, 0x1F28 }, | |
251 { 0x1F2F, 0x1F29 }, | |
252 { 0x1F36, 0x1F30 }, | |
253 { 0x1F37, 0x1F31 }, | |
254 { 0x1F3E, 0x1F38 }, | |
255 { 0x1F3F, 0x1F39 }, | |
256 { 0x1F56, 0x1F50 }, | |
257 { 0x1F57, 0x1F51 }, | |
258 { 0x1F5F, 0x1F59 }, | |
259 { 0x1F66, 0x1F60 }, | |
260 { 0x1F67, 0x1F61 }, | |
261 { 0x1F6E, 0x1F68 }, | |
262 { 0x1F6F, 0x1F69 }, | |
263 { 0x1FCF, 0x1FBF }, | |
264 { 0x1FDF, 0x1FFE }, | |
265 { 0, 0 } | |
266 }; | |
267 | |
268 static HB_UChar16 compose_0x342(HB_UChar16 base) | |
269 { | |
270 const hb_greek_decomposition *d = decompose_0x342; | |
271 while (d->base && d->base != base) | |
272 ++d; | |
273 return d->composed; | |
274 } | |
275 | |
276 static const hb_greek_decomposition decompose_0x345[] = { | |
277 { 0x1FBC, 0x0391 }, | |
278 { 0x1FCC, 0x0397 }, | |
279 { 0x1FFC, 0x03A9 }, | |
280 { 0x1FB4, 0x03AC }, | |
281 { 0x1FC4, 0x03AE }, | |
282 { 0x1FB3, 0x03B1 }, | |
283 { 0x1FC3, 0x03B7 }, | |
284 { 0x1FF3, 0x03C9 }, | |
285 { 0x1FF4, 0x03CE }, | |
286 { 0x1F80, 0x1F00 }, | |
287 { 0x1F81, 0x1F01 }, | |
288 { 0x1F82, 0x1F02 }, | |
289 { 0x1F83, 0x1F03 }, | |
290 { 0x1F84, 0x1F04 }, | |
291 { 0x1F85, 0x1F05 }, | |
292 { 0x1F86, 0x1F06 }, | |
293 { 0x1F87, 0x1F07 }, | |
294 { 0x1F88, 0x1F08 }, | |
295 { 0x1F89, 0x1F09 }, | |
296 { 0x1F8A, 0x1F0A }, | |
297 { 0x1F8B, 0x1F0B }, | |
298 { 0x1F8C, 0x1F0C }, | |
299 { 0x1F8D, 0x1F0D }, | |
300 { 0x1F8E, 0x1F0E }, | |
301 { 0x1F8F, 0x1F0F }, | |
302 { 0x1F90, 0x1F20 }, | |
303 { 0x1F91, 0x1F21 }, | |
304 { 0x1F92, 0x1F22 }, | |
305 { 0x1F93, 0x1F23 }, | |
306 { 0x1F94, 0x1F24 }, | |
307 { 0x1F95, 0x1F25 }, | |
308 { 0x1F96, 0x1F26 }, | |
309 { 0x1F97, 0x1F27 }, | |
310 { 0x1F98, 0x1F28 }, | |
311 { 0x1F99, 0x1F29 }, | |
312 { 0x1F9A, 0x1F2A }, | |
313 { 0x1F9B, 0x1F2B }, | |
314 { 0x1F9C, 0x1F2C }, | |
315 { 0x1F9D, 0x1F2D }, | |
316 { 0x1F9E, 0x1F2E }, | |
317 { 0x1F9F, 0x1F2F }, | |
318 { 0x1FA0, 0x1F60 }, | |
319 { 0x1FA1, 0x1F61 }, | |
320 { 0x1FA2, 0x1F62 }, | |
321 { 0x1FA3, 0x1F63 }, | |
322 { 0x1FA4, 0x1F64 }, | |
323 { 0x1FA5, 0x1F65 }, | |
324 { 0x1FA6, 0x1F66 }, | |
325 { 0x1FA7, 0x1F67 }, | |
326 { 0x1FA8, 0x1F68 }, | |
327 { 0x1FA9, 0x1F69 }, | |
328 { 0x1FAA, 0x1F6A }, | |
329 { 0x1FAB, 0x1F6B }, | |
330 { 0x1FAC, 0x1F6C }, | |
331 { 0x1FAD, 0x1F6D }, | |
332 { 0x1FAE, 0x1F6E }, | |
333 { 0x1FAF, 0x1F6F }, | |
334 { 0x1FB2, 0x1F70 }, | |
335 { 0x1FC2, 0x1F74 }, | |
336 { 0x1FF2, 0x1F7C }, | |
337 { 0x1FB7, 0x1FB6 }, | |
338 { 0x1FC7, 0x1FC6 }, | |
339 { 0x1FF7, 0x1FF6 }, | |
340 { 0, 0 } | |
341 }; | |
342 | |
343 static HB_UChar16 compose_0x345(HB_UChar16 base) | |
344 { | |
345 const hb_greek_decomposition *d = decompose_0x345; | |
346 while (d->base && d->base != base) | |
347 ++d; | |
348 return d->composed; | |
349 } | |
350 | |
351 /* | |
352 Greek shaping. Heuristic positioning can't render polytonic greek correctly. W
e're a lot | |
353 better off mapping greek chars with diacritics to the characters in the extend
ed greek | |
354 region in Unicode if possible. | |
355 */ | |
356 HB_Bool HB_GreekShape(HB_ShaperItem *shaper_item) | |
357 { | |
358 const int availableGlyphs = shaper_item->num_glyphs; | |
359 const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos; | |
360 unsigned short *logClusters = shaper_item->log_clusters; | |
361 HB_GlyphAttributes *attributes = shaper_item->attributes; | |
362 | |
363 HB_Bool haveGlyphs; | |
364 int slen = 1; | |
365 int cluster_start = 0; | |
366 hb_uint32 i; | |
367 | |
368 HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length); | |
369 | |
370 assert(shaper_item->item.script == HB_Script_Greek); | |
371 | |
372 *shapedChars = *uc; | |
373 logClusters[0] = 0; | |
374 | |
375 for (i = 1; i < shaper_item->item.length; ++i) { | |
376 hb_uint16 base = shapedChars[slen-1]; | |
377 hb_uint16 shaped = 0; | |
378 if (uc[i] == 0x300) | |
379 shaped = compose_0x300(base); | |
380 else if (uc[i] == 0x301) | |
381 shaped = compose_0x301(base); | |
382 else if (uc[i] == 0x304) | |
383 shaped = compose_0x304(base); | |
384 else if (uc[i] == 0x306) | |
385 shaped = compose_0x306(base); | |
386 else if (uc[i] == 0x308) | |
387 shaped = compose_0x308(base); | |
388 else if (uc[i] == 0x313) | |
389 shaped = compose_0x313(base); | |
390 else if (uc[i] == 0x314) | |
391 shaped = compose_0x314(base); | |
392 else if (uc[i] == 0x342) | |
393 shaped = compose_0x342(base); | |
394 else if (uc[i] == 0x345) | |
395 shaped = compose_0x345(base); | |
396 | |
397 if (shaped) { | |
398 if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar
16 *)&shaped, 1)) { | |
399 shapedChars[slen-1] = shaped; | |
400 } else { | |
401 shaped = 0; | |
402 } | |
403 } | |
404 | |
405 if (!shaped) { | |
406 HB_CharCategory category; | |
407 int cmb; | |
408 shapedChars[slen] = uc[i]; | |
409 HB_GetUnicodeCharProperties(uc[i], &category, &cmb); | |
410 if (category != HB_Mark_NonSpacing) { | |
411 attributes[slen].clusterStart = TRUE; | |
412 attributes[slen].mark = FALSE; | |
413 attributes[slen].combiningClass = 0; | |
414 attributes[slen].dontPrint = HB_IsControlChar(uc[i]); | |
415 cluster_start = slen; | |
416 } else { | |
417 attributes[slen].clusterStart = FALSE; | |
418 attributes[slen].mark = TRUE; | |
419 attributes[slen].combiningClass = cmb; | |
420 } | |
421 ++slen; | |
422 } | |
423 logClusters[i] = cluster_start; | |
424 } | |
425 | |
426 haveGlyphs = shaper_item->font->klass | |
427 ->convertStringToGlyphIndices(shaper_item->font, | |
428 shapedChars, slen, | |
429 shaper_item->glyphs, &shaper_item->num_gly
phs, | |
430 shaper_item->item.bidiLevel % 2); | |
431 | |
432 HB_FREE_STACKARRAY(shapedChars); | |
433 | |
434 if (!haveGlyphs) | |
435 return FALSE; | |
436 | |
437 #ifndef NO_OPENTYPE | |
438 if (HB_SelectScript(shaper_item, greek_features)) { | |
439 HB_OpenTypeShape(shaper_item, /*properties*/0); | |
440 return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters
*/TRUE); | |
441 } | |
442 #endif | |
443 HB_HeuristicPosition(shaper_item); | |
444 | |
445 return TRUE; | |
446 } | |
447 | |
OLD | NEW |