hb-graphite2.cc 10.5 KB
Newer Older
1
/*
B
Behdad Esfahbod 已提交
2 3
 * Copyright © 2011  Martin Hosken
 * Copyright © 2011  SIL International
4
 * Copyright © 2011,2012  Google, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
B
Behdad Esfahbod 已提交
25 26
 *
 * Google Author(s): Behdad Esfahbod
27 28
 */

29 30 31 32
#define HB_SHAPER graphite2
#define hb_graphite2_shaper_font_data_t gr_font
#include "hb-shaper-impl-private.hh"

B
Behdad Esfahbod 已提交
33 34
#include "hb-graphite2.h"

B
Behdad Esfahbod 已提交
35 36
#include <graphite2/Segment.h>

37
#include "hb-ot-tag.h"
B
Behdad Esfahbod 已提交
38

39

40 41
HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, face)
HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, font)
42 43


44 45 46
/*
 * shaper face data
 */
47

48 49
typedef struct hb_graphite2_tablelist_t {
  struct hb_graphite2_tablelist_t *next;
B
Behdad Esfahbod 已提交
50
  hb_blob_t *blob;
B
Behdad Esfahbod 已提交
51
  unsigned int tag;
52
} hb_graphite2_tablelist_t;
53

54 55
struct hb_graphite2_shaper_face_data_t {
  hb_face_t *face;
B
Behdad Esfahbod 已提交
56
  gr_face   *grface;
57 58
  hb_graphite2_tablelist_t *tlist;
};
59

B
Behdad Esfahbod 已提交
60
static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
61
{
B
Behdad Esfahbod 已提交
62 63 64 65 66 67 68 69 70 71 72 73
  hb_graphite2_shaper_face_data_t *face_data = (hb_graphite2_shaper_face_data_t *) data;
  hb_graphite2_tablelist_t *tlist = face_data->tlist;

  hb_blob_t *blob = NULL;

  for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next)
    if (p->tag == tag) {
      blob = p->blob;
      break;
    }

  if (unlikely (!blob))
B
Behdad Esfahbod 已提交
74
  {
B
Behdad Esfahbod 已提交
75
    blob = face_data->face->reference_table (tag);
B
Behdad Esfahbod 已提交
76 77 78

    hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
    if (unlikely (!p)) {
B
Minor  
Behdad Esfahbod 已提交
79
      hb_blob_destroy (blob);
B
Behdad Esfahbod 已提交
80 81
      return NULL;
    }
B
Behdad Esfahbod 已提交
82 83 84 85 86 87 88
    p->blob = blob;
    p->tag = tag;

    /* TODO Not thread-safe, but fairly harmless.
     * We can do the double-chcked pointer cmpexch thing here. */
    p->next = face_data->tlist;
    face_data->tlist = p;
B
Behdad Esfahbod 已提交
89 90 91 92 93 94
  }

  unsigned int tlen;
  const char *d = hb_blob_get_data (blob, &tlen);
  *len = tlen;
  return d;
95 96
}

97 98
hb_graphite2_shaper_face_data_t *
_hb_graphite2_shaper_face_data_create (hb_face_t *face)
99
{
B
Behdad Esfahbod 已提交
100
  hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF);
B
Behdad Esfahbod 已提交
101 102
  /* Umm, we just reference the table to check whether it exists.
   * Maybe add better API for this? */
103 104 105 106 107
  if (!hb_blob_get_length (silf_blob))
  {
    hb_blob_destroy (silf_blob);
    return NULL;
  }
B
Behdad Esfahbod 已提交
108 109 110 111 112
  hb_blob_destroy (silf_blob);

  hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t));
  if (unlikely (!data))
    hb_blob_destroy (silf_blob);
113 114

  data->face = face;
B
Behdad Esfahbod 已提交
115
  data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
116

B
Behdad Esfahbod 已提交
117 118 119 120 121
  if (unlikely (!data->grface)) {
    free (data);
    return NULL;
  }

122
  return data;
123 124
}

125 126
void
_hb_graphite2_shaper_face_data_destroy (hb_graphite2_shaper_face_data_t *data)
127
{
128 129
  hb_graphite2_tablelist_t *tlist = data->tlist;

B
Behdad Esfahbod 已提交
130 131
  while (tlist)
  {
132
    hb_graphite2_tablelist_t *old = tlist;
B
Behdad Esfahbod 已提交
133 134
    hb_blob_destroy (tlist->blob);
    tlist = tlist->next;
B
Minor  
Behdad Esfahbod 已提交
135
    free (old);
B
Behdad Esfahbod 已提交
136
  }
137

138
  gr_face_destroy (data->grface);
139

140
  free (data);
141 142
}

143 144 145 146 147 148 149
gr_face *
hb_graphite2_face_get_gr_face (hb_face_t *face)
{
  if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return NULL;
  return HB_SHAPER_DATA_GET (face)->grface;
}

B
Behdad Esfahbod 已提交
150

151 152 153
/*
 * shaper font data
 */
B
Behdad Esfahbod 已提交
154

B
Behdad Esfahbod 已提交
155
static float hb_graphite2_get_advance (const void *hb_font, unsigned short gid)
156 157 158
{
  return ((hb_font_t *) hb_font)->get_glyph_h_advance (gid);
}
B
Behdad Esfahbod 已提交
159

160 161 162 163
hb_graphite2_shaper_font_data_t *
_hb_graphite2_shaper_font_data_create (hb_font_t *font)
{
  if (unlikely (!hb_graphite2_shaper_face_data_ensure (font->face))) return NULL;
B
Behdad Esfahbod 已提交
164

165 166
  hb_face_t *face = font->face;
  hb_graphite2_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
B
Behdad Esfahbod 已提交
167

B
Behdad Esfahbod 已提交
168
  return gr_make_font_with_advance_fn (font->x_scale, font, &hb_graphite2_get_advance, face_data->grface);
169 170
}

171 172
void
_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data)
173
{
174 175
  gr_font_destroy (data);
}
B
Behdad Esfahbod 已提交
176

177 178 179 180 181 182 183
gr_font *
hb_graphite2_font_get_gr_font (hb_font_t *font)
{
  if (unlikely (!hb_graphite2_shaper_font_data_ensure (font))) return NULL;
  return HB_SHAPER_DATA_GET (font);
}

B
Behdad Esfahbod 已提交
184

185 186 187
/*
 * shaper shape_plan data
 */
B
Behdad Esfahbod 已提交
188

189
struct hb_graphite2_shaper_shape_plan_data_t {};
B
Behdad Esfahbod 已提交
190

191
hb_graphite2_shaper_shape_plan_data_t *
B
Minor  
Behdad Esfahbod 已提交
192 193 194
_hb_graphite2_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
					     const hb_feature_t *user_features HB_UNUSED,
					     unsigned int        num_user_features HB_UNUSED)
195 196 197
{
  return (hb_graphite2_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
B
Behdad Esfahbod 已提交
198

199
void
B
Minor  
Behdad Esfahbod 已提交
200
_hb_graphite2_shaper_shape_plan_data_destroy (hb_graphite2_shaper_shape_plan_data_t *data HB_UNUSED)
201 202
{
}
B
Behdad Esfahbod 已提交
203 204


205 206 207
/*
 * shaper
 */
208

209 210 211 212 213 214
struct hb_graphite2_cluster_t {
  unsigned int base_char;
  unsigned int num_chars;
  unsigned int base_glyph;
  unsigned int num_glyphs;
};
215

B
Behdad Esfahbod 已提交
216
hb_bool_t
217 218 219 220 221
_hb_graphite2_shape (hb_shape_plan_t    *shape_plan,
		     hb_font_t          *font,
		     hb_buffer_t        *buffer,
		     const hb_feature_t *features,
		     unsigned int        num_features)
222
{
223 224 225
  hb_face_t *face = font->face;
  gr_face *grface = HB_SHAPER_DATA_GET (face)->grface;
  gr_font *grfont = HB_SHAPER_DATA_GET (font);
B
Behdad Esfahbod 已提交
226 227

  const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
228
  const char *lang_end = lang ? strchr (lang, '-') : NULL;
229
  int lang_len = lang_end ? lang_end - lang : -1;
230
  gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
B
Behdad Esfahbod 已提交
231 232 233

  while (num_features--)
  {
234
    const gr_feature_ref *fref = gr_face_find_fref (grface, features->tag);
B
Behdad Esfahbod 已提交
235 236 237 238 239 240 241 242 243 244
    if (fref)
      gr_fref_set_feature_value (fref, features->value, feats);
    features++;
  }

  gr_segment *seg = NULL;
  const gr_slot *is;
  unsigned int ci = 0, ic = 0;
  float curradvx = 0., curradvy = 0.;

245 246 247 248 249 250 251 252 253
  unsigned int scratch_size;
  char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);

#define ALLOCATE_ARRAY(Type, name, len) \
  Type *name = (Type *) scratch; \
  scratch += (len) * sizeof ((name)[0]); \
  scratch_size -= (len) * sizeof ((name)[0]);

  ALLOCATE_ARRAY (uint32_t, chars, buffer->len);
B
Behdad Esfahbod 已提交
254

255 256
  for (unsigned int i = 0; i < buffer->len; ++i)
    chars[i] = buffer->info[i].codepoint;
B
Behdad Esfahbod 已提交
257 258

  hb_tag_t script_tag[2];
B
Minor  
Behdad Esfahbod 已提交
259
  hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
B
Behdad Esfahbod 已提交
260

261
  seg = gr_make_seg (grfont, grface,
B
Behdad Esfahbod 已提交
262 263
		     script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
		     feats,
264
		     gr_utf32, chars, buffer->len,
B
Minor  
Behdad Esfahbod 已提交
265
		     2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
B
Behdad Esfahbod 已提交
266

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
  if (unlikely (!seg)) {
    if (feats) gr_featureval_destroy (feats);
    return false;
  }

  unsigned int glyph_count = gr_seg_n_slots (seg);
  if (unlikely (!glyph_count)) {
    if (feats) gr_featureval_destroy (feats);
    gr_seg_destroy (seg);
    return false;
  }

  scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
  while ((sizeof (hb_graphite2_cluster_t) * buffer->len +
	  sizeof (hb_codepoint_t) * glyph_count) > scratch_size)
  {
    buffer->ensure (buffer->allocated * 2);
    if (unlikely (buffer->in_error)) {
      if (feats) gr_featureval_destroy (feats);
      gr_seg_destroy (seg);
      return false;
    }
    scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
  }
B
Behdad Esfahbod 已提交
291

292 293
  ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
  ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
B
Behdad Esfahbod 已提交
294

295 296 297
  memset (clusters, 0, sizeof (clusters[0]) * buffer->len);

  hb_codepoint_t *pg = gids;
B
Behdad Esfahbod 已提交
298 299 300 301 302 303 304
  for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
  {
    unsigned int before = gr_slot_before (is);
    unsigned int after = gr_slot_after (is);
    *pg = gr_slot_gid (is);
    pg++;
    while (clusters[ci].base_char > before && ci)
305
    {
B
Behdad Esfahbod 已提交
306 307
      clusters[ci-1].num_chars += clusters[ci].num_chars;
      clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
B
Minor  
Behdad Esfahbod 已提交
308
      ci--;
309 310
    }

B
Behdad Esfahbod 已提交
311
    if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
312
    {
313
      hb_graphite2_cluster_t *c = clusters + ci + 1;
B
Behdad Esfahbod 已提交
314 315 316 317
      c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
      c->num_chars = before - c->base_char;
      c->base_glyph = ic;
      c->num_glyphs = 0;
B
Minor  
Behdad Esfahbod 已提交
318
      ci++;
319
    }
B
Minor  
Behdad Esfahbod 已提交
320
    clusters[ci].num_glyphs++;
B
Behdad Esfahbod 已提交
321 322 323 324

    if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
	clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
  }
B
Minor  
Behdad Esfahbod 已提交
325
  ci++;
B
Behdad Esfahbod 已提交
326

B
Behdad Esfahbod 已提交
327
  //buffer->clear_output ();
B
Minor  
Behdad Esfahbod 已提交
328
  for (unsigned int i = 0; i < ci; ++i)
B
Behdad Esfahbod 已提交
329 330 331 332 333 334 335 336 337 338
  {
    for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
    {
      hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
      info->codepoint = gids[clusters[i].base_glyph + j];
      info->cluster = gr_cinfo_base(gr_seg_cinfo(seg, clusters[i].base_char));
    }
  }
  buffer->len = glyph_count;
  //buffer->swap_buffers ();
B
Behdad Esfahbod 已提交
339

340 341 342
  if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
    curradvx = gr_seg_advance_X(seg);

B
Behdad Esfahbod 已提交
343
  hb_glyph_position_t *pPos;
B
Minor  
Behdad Esfahbod 已提交
344 345
  for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
       is; pPos++, is = gr_slot_next_in_segment (is))
B
Behdad Esfahbod 已提交
346
  {
347 348 349 350 351 352 353 354 355 356
    pPos->x_offset = gr_slot_origin_X (is) - curradvx;
    pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
    pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
    pPos->y_advance = gr_slot_advance_Y (is, grface, grfont);
    if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
      curradvx -= pPos->x_advance;
    pPos->x_offset = gr_slot_origin_X (is) - curradvx;
    if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
      curradvx += pPos->x_advance;
    pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
B
Behdad Esfahbod 已提交
357 358
    curradvy += pPos->y_advance;
  }
359 360 361 362 363
  if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
    pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;

  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
    hb_buffer_reverse_clusters (buffer);
364

B
Behdad Esfahbod 已提交
365
  if (feats) gr_featureval_destroy (feats);
366 367 368
  gr_seg_destroy (seg);

  return true;
369
}