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
30static 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
43typedef struct _hb_greek_decomposition {
44    HB_UChar16 composed;
45    HB_UChar16 base;
46} hb_greek_decomposition;
47
48static 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
69static 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
88static 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
110static 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
128static 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
138static 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
146static 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
156static 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
164static 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
173static 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
182static 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
200static 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
208static 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
228static 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
236static 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
268static 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
276static 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
343static 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*/
356HB_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