gfx/harfbuzz/src/hb-graphite2.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/harfbuzz/src/hb-graphite2.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,373 @@
     1.4 +/*
     1.5 + * Copyright © 2011  Martin Hosken
     1.6 + * Copyright © 2011  SIL International
     1.7 + * Copyright © 2011,2012  Google, Inc.
     1.8 + *
     1.9 + *  This is part of HarfBuzz, a text shaping library.
    1.10 + *
    1.11 + * Permission is hereby granted, without written agreement and without
    1.12 + * license or royalty fees, to use, copy, modify, and distribute this
    1.13 + * software and its documentation for any purpose, provided that the
    1.14 + * above copyright notice and the following two paragraphs appear in
    1.15 + * all copies of this software.
    1.16 + *
    1.17 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    1.18 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    1.19 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    1.20 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    1.21 + * DAMAGE.
    1.22 + *
    1.23 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    1.24 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    1.25 + * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    1.26 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    1.27 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    1.28 + *
    1.29 + * Google Author(s): Behdad Esfahbod
    1.30 + */
    1.31 +
    1.32 +#define HB_SHAPER graphite2
    1.33 +#define hb_graphite2_shaper_font_data_t gr_font
    1.34 +#include "hb-shaper-impl-private.hh"
    1.35 +
    1.36 +#include "hb-graphite2.h"
    1.37 +
    1.38 +#include <graphite2/Segment.h>
    1.39 +
    1.40 +
    1.41 +HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, face)
    1.42 +HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, font)
    1.43 +
    1.44 +
    1.45 +/*
    1.46 + * shaper face data
    1.47 + */
    1.48 +
    1.49 +typedef struct hb_graphite2_tablelist_t {
    1.50 +  struct hb_graphite2_tablelist_t *next;
    1.51 +  hb_blob_t *blob;
    1.52 +  unsigned int tag;
    1.53 +} hb_graphite2_tablelist_t;
    1.54 +
    1.55 +struct hb_graphite2_shaper_face_data_t {
    1.56 +  hb_face_t *face;
    1.57 +  gr_face   *grface;
    1.58 +  hb_graphite2_tablelist_t *tlist;
    1.59 +};
    1.60 +
    1.61 +static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
    1.62 +{
    1.63 +  hb_graphite2_shaper_face_data_t *face_data = (hb_graphite2_shaper_face_data_t *) data;
    1.64 +  hb_graphite2_tablelist_t *tlist = face_data->tlist;
    1.65 +
    1.66 +  hb_blob_t *blob = NULL;
    1.67 +
    1.68 +  for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next)
    1.69 +    if (p->tag == tag) {
    1.70 +      blob = p->blob;
    1.71 +      break;
    1.72 +    }
    1.73 +
    1.74 +  if (unlikely (!blob))
    1.75 +  {
    1.76 +    blob = face_data->face->reference_table (tag);
    1.77 +
    1.78 +    hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
    1.79 +    if (unlikely (!p)) {
    1.80 +      hb_blob_destroy (blob);
    1.81 +      return NULL;
    1.82 +    }
    1.83 +    p->blob = blob;
    1.84 +    p->tag = tag;
    1.85 +
    1.86 +    /* TODO Not thread-safe, but fairly harmless.
    1.87 +     * We can do the double-chcked pointer cmpexch thing here. */
    1.88 +    p->next = face_data->tlist;
    1.89 +    face_data->tlist = p;
    1.90 +  }
    1.91 +
    1.92 +  unsigned int tlen;
    1.93 +  const char *d = hb_blob_get_data (blob, &tlen);
    1.94 +  *len = tlen;
    1.95 +  return d;
    1.96 +}
    1.97 +
    1.98 +hb_graphite2_shaper_face_data_t *
    1.99 +_hb_graphite2_shaper_face_data_create (hb_face_t *face)
   1.100 +{
   1.101 +  hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF);
   1.102 +  /* Umm, we just reference the table to check whether it exists.
   1.103 +   * Maybe add better API for this? */
   1.104 +  if (!hb_blob_get_length (silf_blob))
   1.105 +  {
   1.106 +    hb_blob_destroy (silf_blob);
   1.107 +    return NULL;
   1.108 +  }
   1.109 +  hb_blob_destroy (silf_blob);
   1.110 +
   1.111 +  hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t));
   1.112 +  if (unlikely (!data))
   1.113 +    return NULL;
   1.114 +
   1.115 +  data->face = face;
   1.116 +  data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
   1.117 +
   1.118 +  if (unlikely (!data->grface)) {
   1.119 +    free (data);
   1.120 +    return NULL;
   1.121 +  }
   1.122 +
   1.123 +  return data;
   1.124 +}
   1.125 +
   1.126 +void
   1.127 +_hb_graphite2_shaper_face_data_destroy (hb_graphite2_shaper_face_data_t *data)
   1.128 +{
   1.129 +  hb_graphite2_tablelist_t *tlist = data->tlist;
   1.130 +
   1.131 +  while (tlist)
   1.132 +  {
   1.133 +    hb_graphite2_tablelist_t *old = tlist;
   1.134 +    hb_blob_destroy (tlist->blob);
   1.135 +    tlist = tlist->next;
   1.136 +    free (old);
   1.137 +  }
   1.138 +
   1.139 +  gr_face_destroy (data->grface);
   1.140 +
   1.141 +  free (data);
   1.142 +}
   1.143 +
   1.144 +gr_face *
   1.145 +hb_graphite2_face_get_gr_face (hb_face_t *face)
   1.146 +{
   1.147 +  if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return NULL;
   1.148 +  return HB_SHAPER_DATA_GET (face)->grface;
   1.149 +}
   1.150 +
   1.151 +
   1.152 +/*
   1.153 + * shaper font data
   1.154 + */
   1.155 +
   1.156 +static float hb_graphite2_get_advance (const void *hb_font, unsigned short gid)
   1.157 +{
   1.158 +  return ((hb_font_t *) hb_font)->get_glyph_h_advance (gid);
   1.159 +}
   1.160 +
   1.161 +hb_graphite2_shaper_font_data_t *
   1.162 +_hb_graphite2_shaper_font_data_create (hb_font_t *font)
   1.163 +{
   1.164 +  if (unlikely (!hb_graphite2_shaper_face_data_ensure (font->face))) return NULL;
   1.165 +
   1.166 +  hb_face_t *face = font->face;
   1.167 +  hb_graphite2_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   1.168 +
   1.169 +  return gr_make_font_with_advance_fn (font->x_scale, font, &hb_graphite2_get_advance, face_data->grface);
   1.170 +}
   1.171 +
   1.172 +void
   1.173 +_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data)
   1.174 +{
   1.175 +  gr_font_destroy (data);
   1.176 +}
   1.177 +
   1.178 +gr_font *
   1.179 +hb_graphite2_font_get_gr_font (hb_font_t *font)
   1.180 +{
   1.181 +  if (unlikely (!hb_graphite2_shaper_font_data_ensure (font))) return NULL;
   1.182 +  return HB_SHAPER_DATA_GET (font);
   1.183 +}
   1.184 +
   1.185 +
   1.186 +/*
   1.187 + * shaper shape_plan data
   1.188 + */
   1.189 +
   1.190 +struct hb_graphite2_shaper_shape_plan_data_t {};
   1.191 +
   1.192 +hb_graphite2_shaper_shape_plan_data_t *
   1.193 +_hb_graphite2_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
   1.194 +					     const hb_feature_t *user_features HB_UNUSED,
   1.195 +					     unsigned int        num_user_features HB_UNUSED)
   1.196 +{
   1.197 +  return (hb_graphite2_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
   1.198 +}
   1.199 +
   1.200 +void
   1.201 +_hb_graphite2_shaper_shape_plan_data_destroy (hb_graphite2_shaper_shape_plan_data_t *data HB_UNUSED)
   1.202 +{
   1.203 +}
   1.204 +
   1.205 +
   1.206 +/*
   1.207 + * shaper
   1.208 + */
   1.209 +
   1.210 +struct hb_graphite2_cluster_t {
   1.211 +  unsigned int base_char;
   1.212 +  unsigned int num_chars;
   1.213 +  unsigned int base_glyph;
   1.214 +  unsigned int num_glyphs;
   1.215 +};
   1.216 +
   1.217 +hb_bool_t
   1.218 +_hb_graphite2_shape (hb_shape_plan_t    *shape_plan,
   1.219 +		     hb_font_t          *font,
   1.220 +		     hb_buffer_t        *buffer,
   1.221 +		     const hb_feature_t *features,
   1.222 +		     unsigned int        num_features)
   1.223 +{
   1.224 +  hb_face_t *face = font->face;
   1.225 +  gr_face *grface = HB_SHAPER_DATA_GET (face)->grface;
   1.226 +  gr_font *grfont = HB_SHAPER_DATA_GET (font);
   1.227 +
   1.228 +  const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
   1.229 +  const char *lang_end = lang ? strchr (lang, '-') : NULL;
   1.230 +  int lang_len = lang_end ? lang_end - lang : -1;
   1.231 +  gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
   1.232 +
   1.233 +  while (num_features--)
   1.234 +  {
   1.235 +    const gr_feature_ref *fref = gr_face_find_fref (grface, features->tag);
   1.236 +    if (fref)
   1.237 +      gr_fref_set_feature_value (fref, features->value, feats);
   1.238 +    features++;
   1.239 +  }
   1.240 +
   1.241 +  gr_segment *seg = NULL;
   1.242 +  const gr_slot *is;
   1.243 +  unsigned int ci = 0, ic = 0;
   1.244 +  float curradvx = 0., curradvy = 0.;
   1.245 +
   1.246 +  unsigned int scratch_size;
   1.247 +  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
   1.248 +
   1.249 +  uint32_t *chars = (uint32_t *) scratch;
   1.250 +
   1.251 +  for (unsigned int i = 0; i < buffer->len; ++i)
   1.252 +    chars[i] = buffer->info[i].codepoint;
   1.253 +
   1.254 +  hb_tag_t script_tag[2];
   1.255 +  hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
   1.256 +
   1.257 +  seg = gr_make_seg (grfont, grface,
   1.258 +		     script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
   1.259 +		     feats,
   1.260 +		     gr_utf32, chars, buffer->len,
   1.261 +		     2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
   1.262 +
   1.263 +  if (unlikely (!seg)) {
   1.264 +    if (feats) gr_featureval_destroy (feats);
   1.265 +    return false;
   1.266 +  }
   1.267 +
   1.268 +  unsigned int glyph_count = gr_seg_n_slots (seg);
   1.269 +  if (unlikely (!glyph_count)) {
   1.270 +    if (feats) gr_featureval_destroy (feats);
   1.271 +    gr_seg_destroy (seg);
   1.272 +    return false;
   1.273 +  }
   1.274 +
   1.275 +  scratch = buffer->get_scratch_buffer (&scratch_size);
   1.276 +  while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
   1.277 +	  DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
   1.278 +  {
   1.279 +    buffer->ensure (buffer->allocated * 2);
   1.280 +    if (unlikely (buffer->in_error)) {
   1.281 +      if (feats) gr_featureval_destroy (feats);
   1.282 +      gr_seg_destroy (seg);
   1.283 +      return false;
   1.284 +    }
   1.285 +    scratch = buffer->get_scratch_buffer (&scratch_size);
   1.286 +  }
   1.287 +
   1.288 +#define ALLOCATE_ARRAY(Type, name, len) \
   1.289 +  Type *name = (Type *) scratch; \
   1.290 +  { \
   1.291 +    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
   1.292 +    assert (_consumed <= scratch_size); \
   1.293 +    scratch += _consumed; \
   1.294 +    scratch_size -= _consumed; \
   1.295 +  }
   1.296 +
   1.297 +  ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
   1.298 +  ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
   1.299 +
   1.300 +#undef ALLOCATE_ARRAY
   1.301 +
   1.302 +  memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
   1.303 +
   1.304 +  hb_codepoint_t *pg = gids;
   1.305 +  for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
   1.306 +  {
   1.307 +    unsigned int before = gr_slot_before (is);
   1.308 +    unsigned int after = gr_slot_after (is);
   1.309 +    *pg = gr_slot_gid (is);
   1.310 +    pg++;
   1.311 +    while (clusters[ci].base_char > before && ci)
   1.312 +    {
   1.313 +      clusters[ci-1].num_chars += clusters[ci].num_chars;
   1.314 +      clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
   1.315 +      ci--;
   1.316 +    }
   1.317 +
   1.318 +    if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
   1.319 +    {
   1.320 +      hb_graphite2_cluster_t *c = clusters + ci + 1;
   1.321 +      c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
   1.322 +      c->num_chars = before - c->base_char;
   1.323 +      c->base_glyph = ic;
   1.324 +      c->num_glyphs = 0;
   1.325 +      ci++;
   1.326 +    }
   1.327 +    clusters[ci].num_glyphs++;
   1.328 +
   1.329 +    if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
   1.330 +	clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
   1.331 +  }
   1.332 +  ci++;
   1.333 +
   1.334 +  //buffer->clear_output ();
   1.335 +  for (unsigned int i = 0; i < ci; ++i)
   1.336 +  {
   1.337 +    for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
   1.338 +    {
   1.339 +      hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
   1.340 +      info->codepoint = gids[clusters[i].base_glyph + j];
   1.341 +      info->cluster = gr_cinfo_base(gr_seg_cinfo(seg, clusters[i].base_char));
   1.342 +    }
   1.343 +  }
   1.344 +  buffer->len = glyph_count;
   1.345 +  //buffer->swap_buffers ();
   1.346 +
   1.347 +  if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
   1.348 +    curradvx = gr_seg_advance_X(seg);
   1.349 +
   1.350 +  hb_glyph_position_t *pPos;
   1.351 +  for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
   1.352 +       is; pPos++, is = gr_slot_next_in_segment (is))
   1.353 +  {
   1.354 +    pPos->x_offset = gr_slot_origin_X (is) - curradvx;
   1.355 +    pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
   1.356 +    pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
   1.357 +    pPos->y_advance = gr_slot_advance_Y (is, grface, grfont);
   1.358 +    if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
   1.359 +      curradvx -= pPos->x_advance;
   1.360 +    pPos->x_offset = gr_slot_origin_X (is) - curradvx;
   1.361 +    if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
   1.362 +      curradvx += pPos->x_advance;
   1.363 +    pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
   1.364 +    curradvy += pPos->y_advance;
   1.365 +  }
   1.366 +  if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
   1.367 +    pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
   1.368 +
   1.369 +  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
   1.370 +    hb_buffer_reverse_clusters (buffer);
   1.371 +
   1.372 +  if (feats) gr_featureval_destroy (feats);
   1.373 +  gr_seg_destroy (seg);
   1.374 +
   1.375 +  return true;
   1.376 +}

mercurial