Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2012  Google, Inc.
      3  *
      4  *  This is part of HarfBuzz, a text shaping 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  * Google Author(s): Behdad Esfahbod
     25  */
     26 
     27 #define HB_SHAPER icu_le
     28 #define hb_icu_le_shaper_font_data_t PortableFontInstance
     29 #include "hb-shaper-impl-private.hh"
     30 
     31 #include "hb-icu-le/PortableFontInstance.h"
     32 
     33 #include "layout/loengine.h"
     34 #include "unicode/unistr.h"
     35 
     36 #include "hb-icu.h"
     37 
     38 
     39 /*
     40  * shaper face data
     41  */
     42 
     43 struct hb_icu_le_shaper_face_data_t {};
     44 
     45 hb_icu_le_shaper_face_data_t *
     46 _hb_icu_le_shaper_face_data_create (hb_face_t *face HB_UNUSED)
     47 {
     48   return (hb_icu_le_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
     49 }
     50 
     51 void
     52 _hb_icu_le_shaper_face_data_destroy (hb_icu_le_shaper_face_data_t *data HB_UNUSED)
     53 {
     54 }
     55 
     56 
     57 /*
     58  * shaper font data
     59  */
     60 
     61 hb_icu_le_shaper_font_data_t *
     62 _hb_icu_le_shaper_font_data_create (hb_font_t *font)
     63 {
     64   LEErrorCode status = LE_NO_ERROR;
     65   hb_icu_le_shaper_font_data_t *data = new PortableFontInstance (font->face,
     66 								 font->x_scale,
     67 								 font->y_scale,
     68 								 status);
     69   if (status != LE_NO_ERROR) {
     70     delete (data);
     71     return NULL;
     72   }
     73 
     74   return data;
     75 }
     76 
     77 void
     78 _hb_icu_le_shaper_font_data_destroy (hb_icu_le_shaper_font_data_t *data)
     79 {
     80   delete (data);
     81 }
     82 
     83 
     84 /*
     85  * shaper shape_plan data
     86  */
     87 
     88 struct hb_icu_le_shaper_shape_plan_data_t {};
     89 
     90 hb_icu_le_shaper_shape_plan_data_t *
     91 _hb_icu_le_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
     92 					  const hb_feature_t *user_features,
     93 					  unsigned int        num_user_features)
     94 {
     95   return (hb_icu_le_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
     96 }
     97 
     98 void
     99 _hb_icu_le_shaper_shape_plan_data_destroy (hb_icu_le_shaper_shape_plan_data_t *data)
    100 {
    101 }
    102 
    103 
    104 /*
    105  * shaper
    106  */
    107 
    108 hb_bool_t
    109 _hb_icu_le_shape (hb_shape_plan_t    *shape_plan,
    110 		  hb_font_t          *font,
    111 		  hb_buffer_t        *buffer,
    112 		  const hb_feature_t *features,
    113 		  unsigned int        num_features)
    114 {
    115   LEFontInstance *font_instance = HB_SHAPER_DATA_GET (font);
    116   le_int32 script_code = hb_icu_script_from_script (shape_plan->props.script);
    117   le_int32 language_code = -1 /* TODO */;
    118   le_int32 typography_flags = 3; /* Needed for ligatures and kerning */
    119   LEErrorCode status = LE_NO_ERROR;
    120   le_engine *le = le_create ((const le_font *) font_instance,
    121 			     script_code,
    122 			     language_code,
    123 			     typography_flags,
    124 			     &status);
    125   if (status != LE_NO_ERROR)
    126   { le_close (le); return false; }
    127 
    128 retry:
    129 
    130   unsigned int scratch_size;
    131   char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
    132 
    133 #define ALLOCATE_ARRAY(Type, name, len) \
    134   Type *name = (Type *) scratch; \
    135   scratch += (len) * sizeof ((name)[0]); \
    136   scratch_size -= (len) * sizeof ((name)[0]);
    137 
    138   ALLOCATE_ARRAY (LEUnicode, chars, buffer->len);
    139   ALLOCATE_ARRAY (unsigned int, clusters, buffer->len);
    140 
    141   /* XXX Use UTF-16 decoder! */
    142   for (unsigned int i = 0; i < buffer->len; i++) {
    143     chars[i] = buffer->info[i].codepoint;
    144     clusters[i] = buffer->info[i].cluster;
    145   }
    146 
    147   unsigned int glyph_count = le_layoutChars (le,
    148 					     chars,
    149 					     0,
    150 					     buffer->len,
    151 					     buffer->len,
    152 					     HB_DIRECTION_IS_BACKWARD (buffer->props.direction),
    153 					     0., 0.,
    154 					     &status);
    155   if (status != LE_NO_ERROR)
    156   { le_close (le); return false; }
    157 
    158   unsigned int num_glyphs = scratch_size / (sizeof (LEGlyphID) +
    159 					    sizeof (le_int32) +
    160 					    sizeof (float) * 2);
    161 
    162   if (unlikely (glyph_count >= num_glyphs || glyph_count > buffer->allocated)) {
    163     buffer->ensure (buffer->allocated * 2);
    164     if (buffer->in_error)
    165     { le_close (le); return false; }
    166     goto retry;
    167   }
    168 
    169   ALLOCATE_ARRAY (LEGlyphID, glyphs, glyph_count);
    170   ALLOCATE_ARRAY (le_int32, indices, glyph_count);
    171   ALLOCATE_ARRAY (float, positions, glyph_count * 2 + 2);
    172 
    173   le_getGlyphs (le, glyphs, &status);
    174   le_getCharIndices (le, indices, &status);
    175   le_getGlyphPositions (le, positions, &status);
    176 
    177 #undef ALLOCATE_ARRAY
    178 
    179   /* Ok, we've got everything we need, now compose output buffer,
    180    * very, *very*, carefully! */
    181 
    182   unsigned int j = 0;
    183   hb_glyph_info_t *info = buffer->info;
    184   for (unsigned int i = 0; i < glyph_count; i++)
    185   {
    186     if (glyphs[i] >= 0xFFFE)
    187 	continue;
    188 
    189     info[j].codepoint = glyphs[i];
    190     info[j].cluster = clusters[indices[i]];
    191 
    192     /* icu-le doesn't seem to have separate advance values. */
    193     info[j].mask = positions[2 * i + 2] - positions[2 * i];
    194     info[j].var1.u32 = 0;
    195     info[j].var2.u32 = -positions[2 * i + 1];
    196 
    197     j++;
    198   }
    199   buffer->len = j;
    200 
    201   buffer->clear_positions ();
    202 
    203   for (unsigned int i = 0; i < buffer->len; i++) {
    204     hb_glyph_info_t *info = &buffer->info[i];
    205     hb_glyph_position_t *pos = &buffer->pos[i];
    206 
    207     /* TODO vertical */
    208     pos->x_advance = info->mask;
    209     pos->x_offset = info->var1.u32;
    210     pos->y_offset = info->var2.u32;
    211   }
    212 
    213   le_close (le);
    214   return true;
    215 }
    216