• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
compose_0x300(HB_UChar16 base)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 
compose_0x301(HB_UChar16 base)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 
compose_0x304(HB_UChar16 base)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 
compose_0x306(HB_UChar16 base)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 
compose_0x308(HB_UChar16 base)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 
compose_0x313(HB_UChar16 base)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 
compose_0x314(HB_UChar16 base)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 
compose_0x342(HB_UChar16 base)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 
compose_0x345(HB_UChar16 base)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. We're a lot
353   better off mapping greek chars with diacritics to the characters in the extended greek
354   region in Unicode if possible.
355 */
HB_GreekShape(HB_ShaperItem * shaper_item)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_UChar16 *)&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_glyphs,
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 
448