Home | History | Annotate | Download | only in src
      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. 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 */
    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