Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2012  Mozilla Foundation.
      3  * Copyright  2012  Google, Inc.
      4  *
      5  *  This is part of HarfBuzz, a text shaping library.
      6  *
      7  * Permission is hereby granted, without written agreement and without
      8  * license or royalty fees, to use, copy, modify, and distribute this
      9  * software and its documentation for any purpose, provided that the
     10  * above copyright notice and the following two paragraphs appear in
     11  * all copies of this software.
     12  *
     13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     17  * DAMAGE.
     18  *
     19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     24  *
     25  * Mozilla Author(s): Jonathan Kew
     26  * Google Author(s): Behdad Esfahbod
     27  */
     28 
     29 #define HB_SHAPER coretext
     30 #include "hb-shaper-impl-private.hh"
     31 
     32 #include "hb-coretext.h"
     33 
     34 
     35 #ifndef HB_DEBUG_CORETEXT
     36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0)
     37 #endif
     38 
     39 
     40 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
     41 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
     42 
     43 
     44 /*
     45  * shaper face data
     46  */
     47 
     48 struct hb_coretext_shaper_face_data_t {
     49   CGFontRef cg_font;
     50 };
     51 
     52 static void
     53 release_data (void *info, const void *data, size_t size)
     54 {
     55   assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
     56           hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
     57 
     58   hb_blob_destroy ((hb_blob_t *) info);
     59 }
     60 
     61 hb_coretext_shaper_face_data_t *
     62 _hb_coretext_shaper_face_data_create (hb_face_t *face)
     63 {
     64   hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
     65   if (unlikely (!data))
     66     return NULL;
     67 
     68   hb_blob_t *blob = hb_face_reference_blob (face);
     69   unsigned int blob_length;
     70   const char *blob_data = hb_blob_get_data (blob, &blob_length);
     71   if (unlikely (!blob_length))
     72     DEBUG_MSG (CORETEXT, face, "Face has empty blob");
     73 
     74   CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
     75   data->cg_font = CGFontCreateWithDataProvider (provider);
     76   CGDataProviderRelease (provider);
     77 
     78   if (unlikely (!data->cg_font)) {
     79     DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
     80     free (data);
     81     return NULL;
     82   }
     83 
     84   return data;
     85 }
     86 
     87 void
     88 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
     89 {
     90   CFRelease (data->cg_font);
     91   free (data);
     92 }
     93 
     94 CGFontRef
     95 hb_coretext_face_get_cg_font (hb_face_t *face)
     96 {
     97   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
     98   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
     99   return face_data->cg_font;
    100 }
    101 
    102 
    103 /*
    104  * shaper font data
    105  */
    106 
    107 struct hb_coretext_shaper_font_data_t {
    108   CTFontRef ct_font;
    109 };
    110 
    111 hb_coretext_shaper_font_data_t *
    112 _hb_coretext_shaper_font_data_create (hb_font_t *font)
    113 {
    114   if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
    115 
    116   hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
    117   if (unlikely (!data))
    118     return NULL;
    119 
    120   hb_face_t *face = font->face;
    121   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    122 
    123   data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scale, NULL, NULL);
    124   if (unlikely (!data->ct_font)) {
    125     DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
    126     free (data);
    127     return NULL;
    128   }
    129 
    130   return data;
    131 }
    132 
    133 void
    134 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
    135 {
    136   CFRelease (data->ct_font);
    137   free (data);
    138 }
    139 
    140 
    141 /*
    142  * shaper shape_plan data
    143  */
    144 
    145 struct hb_coretext_shaper_shape_plan_data_t {};
    146 
    147 hb_coretext_shaper_shape_plan_data_t *
    148 _hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
    149 					     const hb_feature_t *user_features HB_UNUSED,
    150 					     unsigned int        num_user_features HB_UNUSED)
    151 {
    152   return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
    153 }
    154 
    155 void
    156 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
    157 {
    158 }
    159 
    160 CTFontRef
    161 hb_coretext_font_get_ct_font (hb_font_t *font)
    162 {
    163   if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
    164   hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
    165   return font_data->ct_font;
    166 }
    167 
    168 
    169 /*
    170  * shaper
    171  */
    172 
    173 hb_bool_t
    174 _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
    175 		    hb_font_t          *font,
    176                     hb_buffer_t        *buffer,
    177                     const hb_feature_t *features,
    178                     unsigned int        num_features)
    179 {
    180   hb_face_t *face = font->face;
    181   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    182   hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
    183 
    184 #define FAIL(...) \
    185   HB_STMT_START { \
    186     DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
    187     return false; \
    188   } HB_STMT_END;
    189 
    190   unsigned int scratch_size;
    191   char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
    192 
    193 #define utf16_index() var1.u32
    194 
    195   UniChar *pchars = (UniChar *) scratch;
    196   unsigned int chars_len = 0;
    197   for (unsigned int i = 0; i < buffer->len; i++) {
    198     hb_codepoint_t c = buffer->info[i].codepoint;
    199     buffer->info[i].utf16_index() = chars_len;
    200     if (likely (c < 0x10000))
    201       pchars[chars_len++] = c;
    202     else if (unlikely (c >= 0x110000))
    203       pchars[chars_len++] = 0xFFFD;
    204     else {
    205       pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
    206       pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
    207     }
    208   }
    209 
    210 #undef utf16_index
    211 
    212   CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (kCFAllocatorDefault,
    213                                                                pchars, chars_len,
    214                                                                kCFAllocatorNull);
    215 
    216   CFDictionaryRef attrs = CFDictionaryCreate (kCFAllocatorDefault,
    217                                               (const void**) &kCTFontAttributeName,
    218                                               (const void**) &font_data->ct_font,
    219                                               1, /* count of attributes */
    220                                               &kCFTypeDictionaryKeyCallBacks,
    221                                               &kCFTypeDictionaryValueCallBacks);
    222 
    223   /* TODO: support features */
    224 
    225   CFAttributedStringRef attr_string = CFAttributedStringCreate (kCFAllocatorDefault, string_ref, attrs);
    226   CFRelease (string_ref);
    227   CFRelease (attrs);
    228 
    229   CTLineRef line = CTLineCreateWithAttributedString (attr_string);
    230   CFRelease (attr_string);
    231 
    232   CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
    233   unsigned int num_runs = CFArrayGetCount (glyph_runs);
    234 
    235   bool success = true;
    236   buffer->len = 0;
    237 
    238   const CFRange range_all = CFRangeMake (0, 0);
    239 
    240   for (unsigned int i = 0; i < num_runs; i++) {
    241     CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i);
    242 
    243     unsigned int num_glyphs = CTRunGetGlyphCount (run);
    244     if (num_glyphs == 0)
    245       continue;
    246 
    247     buffer->ensure (buffer->len + num_glyphs);
    248 
    249     /* Testing indicates that CTRunGetGlyphsPtr (almost?) always succeeds,
    250      * and so copying data to our own buffer with CTRunGetGlyphs will be
    251      * extremely rare. */
    252 
    253     unsigned int scratch_size;
    254     char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
    255 
    256 #define ALLOCATE_ARRAY(Type, name, len) \
    257   Type *name = (Type *) scratch; \
    258   scratch += (len) * sizeof ((name)[0]); \
    259   scratch_size -= (len) * sizeof ((name)[0]);
    260 
    261     const CGGlyph* glyphs = CTRunGetGlyphsPtr (run);
    262     if (!glyphs) {
    263       ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs);
    264       CTRunGetGlyphs (run, range_all, glyph_buf);
    265       glyphs = glyph_buf;
    266     }
    267 
    268     const CGPoint* positions = CTRunGetPositionsPtr (run);
    269     if (!positions) {
    270       ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs);
    271       CTRunGetPositions (run, range_all, position_buf);
    272       positions = position_buf;
    273     }
    274 
    275     const CFIndex* string_indices = CTRunGetStringIndicesPtr (run);
    276     if (!string_indices) {
    277       ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs);
    278       CTRunGetStringIndices (run, range_all, index_buf);
    279       string_indices = index_buf;
    280     }
    281 
    282 #undef ALLOCATE_ARRAY
    283 
    284     double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
    285 
    286     for (unsigned int j = 0; j < num_glyphs; j++) {
    287       double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
    288 
    289       hb_glyph_info_t *info = &buffer->info[buffer->len];
    290       hb_glyph_position_t *pos = &buffer->pos[buffer->len];
    291 
    292       info->codepoint = glyphs[j];
    293       info->cluster = string_indices[j];
    294 
    295       /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
    296       info->mask = advance;
    297       info->var1.u32 = 0;
    298       info->var2.u32 = positions[j].y;
    299 
    300       buffer->len++;
    301     }
    302   }
    303 
    304   buffer->clear_positions ();
    305 
    306   unsigned int count = buffer->len;
    307   for (unsigned int i = 0; i < count; ++i) {
    308     hb_glyph_info_t *info = &buffer->info[i];
    309     hb_glyph_position_t *pos = &buffer->pos[i];
    310 
    311     /* TODO vertical */
    312     pos->x_advance = info->mask;
    313     pos->x_offset = info->var1.u32;
    314     pos->y_offset = info->var2.u32;
    315   }
    316 
    317   /* Fix up clusters so that we never return out-of-order indices;
    318    * if core text has reordered glyphs, we'll merge them to the
    319    * beginning of the reordered cluster.
    320    *
    321    * This does *not* mean we'll form the same clusters as Uniscribe
    322    * or the native OT backend, only that the cluster indices will be
    323    * monotonic in the output buffer. */
    324   if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
    325     unsigned int prev_cluster = 0;
    326     for (unsigned int i = 0; i < count; i++) {
    327       unsigned int curr_cluster = buffer->info[i].cluster;
    328       if (curr_cluster < prev_cluster) {
    329         for (unsigned int j = i; j > 0; j--) {
    330           if (buffer->info[j - 1].cluster > curr_cluster)
    331             buffer->info[j - 1].cluster = curr_cluster;
    332           else
    333             break;
    334         }
    335       }
    336       prev_cluster = curr_cluster;
    337     }
    338   } else {
    339     unsigned int prev_cluster = (unsigned int)-1;
    340     for (unsigned int i = 0; i < count; i++) {
    341       unsigned int curr_cluster = buffer->info[i].cluster;
    342       if (curr_cluster > prev_cluster) {
    343         for (unsigned int j = i; j > 0; j--) {
    344           if (buffer->info[j - 1].cluster < curr_cluster)
    345             buffer->info[j - 1].cluster = curr_cluster;
    346           else
    347             break;
    348         }
    349       }
    350       prev_cluster = curr_cluster;
    351     }
    352   }
    353 
    354   return true;
    355 }
    356