hb-graphite2.cc 12.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
#define HB_SHAPER graphite2
30
#include "hb-shaper-impl.hh"
31

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

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

36

B
Behdad Esfahbod 已提交
37 38
HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, face)
HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, font)
39 40


41 42 43
/*
 * shaper face data
 */
44

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

52 53
struct hb_graphite2_face_data_t
{
54
  hb_face_t *face;
B
Behdad Esfahbod 已提交
55
  gr_face   *grface;
56
  hb_atomic_ptr_t<hb_graphite2_tablelist_t> tlist;
57
};
58

B
Behdad Esfahbod 已提交
59
static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
60
{
B
Rename  
Behdad Esfahbod 已提交
61
  hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
62
  hb_graphite2_tablelist_t *tlist = face_data->tlist.get ();
B
Behdad Esfahbod 已提交
63

B
Behdad Esfahbod 已提交
64
  hb_blob_t *blob = nullptr;
B
Behdad Esfahbod 已提交
65 66 67 68 69 70 71 72

  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 已提交
73
  {
B
Behdad Esfahbod 已提交
74
    blob = face_data->face->reference_table (tag);
B
Behdad Esfahbod 已提交
75 76 77

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

84
retry:
85
    hb_graphite2_tablelist_t *tlist = face_data->tlist.get ();
86 87
    p->next = tlist;

88
    if (unlikely (!face_data->tlist.cmpexch (tlist, p)))
89
      goto retry;
B
Behdad Esfahbod 已提交
90 91 92 93 94 95
  }

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

M
mhosken 已提交
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
static void hb_graphite2_release_table(const void *data, const void *table_buffer)
{
  hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
  hb_graphite2_tablelist_t *tlist = face_data->tlist.get();

  hb_graphite2_tablelist_t *prev = nullptr;
  hb_graphite2_tablelist_t *curr = tlist;
  while (curr)
  {
    if (hb_blob_get_data(curr->blob, nullptr) == table_buffer)
    {
      if (prev == nullptr)
        face_data->tlist.cmpexch(tlist, curr->next);
      else
        prev->next = curr->next;
      hb_blob_destroy(curr->blob);
      free(curr);
      break;
    }
    prev = curr;
    curr = curr->next;
  }
}

static gr_face_ops hb_graphite2_face_ops = { sizeof(gr_face_ops), hb_graphite2_get_table, hb_graphite2_release_table };

B
Rename  
Behdad Esfahbod 已提交
124
hb_graphite2_face_data_t *
125
_hb_graphite2_shaper_face_data_create (hb_face_t *face)
126
{
B
Behdad Esfahbod 已提交
127
  hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF);
B
Behdad Esfahbod 已提交
128 129
  /* Umm, we just reference the table to check whether it exists.
   * Maybe add better API for this? */
130 131 132
  if (!hb_blob_get_length (silf_blob))
  {
    hb_blob_destroy (silf_blob);
B
Behdad Esfahbod 已提交
133
    return nullptr;
134
  }
B
Behdad Esfahbod 已提交
135 136
  hb_blob_destroy (silf_blob);

B
Behdad Esfahbod 已提交
137
  hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) calloc (1, sizeof (hb_graphite2_face_data_t));
B
Behdad Esfahbod 已提交
138
  if (unlikely (!data))
B
Behdad Esfahbod 已提交
139
    return nullptr;
140 141

  data->face = face;
M
mhosken 已提交
142
  data->grface = gr_make_face_with_ops (data, &hb_graphite2_face_ops, gr_face_preloadAll);
143

B
Behdad Esfahbod 已提交
144 145
  if (unlikely (!data->grface)) {
    free (data);
B
Behdad Esfahbod 已提交
146
    return nullptr;
B
Behdad Esfahbod 已提交
147 148
  }

149
  return data;
150 151
}

152
void
B
Rename  
Behdad Esfahbod 已提交
153
_hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
154
{
155
  hb_graphite2_tablelist_t *tlist = data->tlist.get ();
156

B
Behdad Esfahbod 已提交
157 158
  while (tlist)
  {
159
    hb_graphite2_tablelist_t *old = tlist;
B
Behdad Esfahbod 已提交
160 161
    hb_blob_destroy (tlist->blob);
    tlist = tlist->next;
B
Minor  
Behdad Esfahbod 已提交
162
    free (old);
B
Behdad Esfahbod 已提交
163
  }
164

165
  gr_face_destroy (data->grface);
166

167
  free (data);
168 169
}

B
Behdad Esfahbod 已提交
170 171 172
/*
 * Since: 0.9.10
 */
173 174 175
gr_face *
hb_graphite2_face_get_gr_face (hb_face_t *face)
{
B
Behdad Esfahbod 已提交
176
  if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return nullptr;
177 178 179
  return HB_SHAPER_DATA_GET (face)->grface;
}

B
Behdad Esfahbod 已提交
180

181 182 183
/*
 * shaper font data
 */
B
Behdad Esfahbod 已提交
184

B
Rename  
Behdad Esfahbod 已提交
185
struct hb_graphite2_font_data_t {};
B
Behdad Esfahbod 已提交
186

B
Rename  
Behdad Esfahbod 已提交
187
hb_graphite2_font_data_t *
188
_hb_graphite2_shaper_font_data_create (hb_font_t *font HB_UNUSED)
189
{
B
Rename  
Behdad Esfahbod 已提交
190
  return (hb_graphite2_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
191 192
}

193
void
B
Rename  
Behdad Esfahbod 已提交
194
_hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED)
195
{
196
}
B
Behdad Esfahbod 已提交
197

B
Behdad Esfahbod 已提交
198 199 200
/*
 * Since: 0.9.10
 */
201 202 203
gr_font *
hb_graphite2_font_get_gr_font (hb_font_t *font)
{
B
Behdad Esfahbod 已提交
204
  return nullptr;
205 206
}

B
Behdad Esfahbod 已提交
207

208 209 210
/*
 * shaper shape_plan data
 */
B
Behdad Esfahbod 已提交
211

B
Rename  
Behdad Esfahbod 已提交
212
struct hb_graphite2_shape_plan_data_t {};
B
Behdad Esfahbod 已提交
213

B
Rename  
Behdad Esfahbod 已提交
214
hb_graphite2_shape_plan_data_t *
B
Minor  
Behdad Esfahbod 已提交
215 216
_hb_graphite2_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
					     const hb_feature_t *user_features HB_UNUSED,
B
Behdad Esfahbod 已提交
217 218 219
					     unsigned int        num_user_features HB_UNUSED,
					     const int          *coords HB_UNUSED,
					     unsigned int        num_coords HB_UNUSED)
220
{
B
Rename  
Behdad Esfahbod 已提交
221
  return (hb_graphite2_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
222
}
B
Behdad Esfahbod 已提交
223

224
void
B
Rename  
Behdad Esfahbod 已提交
225
_hb_graphite2_shaper_shape_plan_data_destroy (hb_graphite2_shape_plan_data_t *data HB_UNUSED)
226 227
{
}
B
Behdad Esfahbod 已提交
228 229


230 231 232
/*
 * shaper
 */
233

234 235 236 237 238
struct hb_graphite2_cluster_t {
  unsigned int base_char;
  unsigned int num_chars;
  unsigned int base_glyph;
  unsigned int num_glyphs;
239
  unsigned int cluster;
240
  float advance;
241
};
242

B
Behdad Esfahbod 已提交
243
hb_bool_t
244 245 246 247 248
_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)
249
{
250 251
  hb_face_t *face = font->face;
  gr_face *grface = HB_SHAPER_DATA_GET (face)->grface;
B
Behdad Esfahbod 已提交
252 253

  const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
B
Behdad Esfahbod 已提交
254
  const char *lang_end = lang ? strchr (lang, '-') : nullptr;
255
  int lang_len = lang_end ? lang_end - lang : -1;
256
  gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
B
Behdad Esfahbod 已提交
257

B
Behdad Esfahbod 已提交
258
  for (unsigned int i = 0; i < num_features; i++)
B
Behdad Esfahbod 已提交
259
  {
B
Behdad Esfahbod 已提交
260
    const gr_feature_ref *fref = gr_face_find_fref (grface, features[i].tag);
B
Behdad Esfahbod 已提交
261
    if (fref)
B
Behdad Esfahbod 已提交
262
      gr_fref_set_feature_value (fref, features[i].value, feats);
B
Behdad Esfahbod 已提交
263 264
  }

B
Behdad Esfahbod 已提交
265
  gr_segment *seg = nullptr;
B
Behdad Esfahbod 已提交
266 267 268 269
  const gr_slot *is;
  unsigned int ci = 0, ic = 0;
  float curradvx = 0., curradvy = 0.;

270
  unsigned int scratch_size;
B
Behdad Esfahbod 已提交
271
  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
272

273
  uint32_t *chars = (uint32_t *) scratch;
B
Behdad Esfahbod 已提交
274

275 276
  for (unsigned int i = 0; i < buffer->len; ++i)
    chars[i] = buffer->info[i].codepoint;
B
Behdad Esfahbod 已提交
277

B
Behdad Esfahbod 已提交
278 279
  /* TODO ensure_native_direction. */

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

B
Behdad Esfahbod 已提交
283
  seg = gr_make_seg (nullptr, grface,
B
Behdad Esfahbod 已提交
284 285
		     script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
		     feats,
286
		     gr_utf32, chars, buffer->len,
B
Minor  
Behdad Esfahbod 已提交
287
		     2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
B
Behdad Esfahbod 已提交
288

289 290 291 292 293 294 295 296 297
  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);
B
Behdad Esfahbod 已提交
298 299
    buffer->len = 0;
    return true;
300 301
  }

B
Behdad Esfahbod 已提交
302
  buffer->ensure (glyph_count);
303 304 305
  scratch = buffer->get_scratch_buffer (&scratch_size);
  while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
	  DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
306
  {
B
Minor  
Behdad Esfahbod 已提交
307 308
    if (unlikely (!buffer->ensure (buffer->allocated * 2)))
    {
309 310 311 312
      if (feats) gr_featureval_destroy (feats);
      gr_seg_destroy (seg);
      return false;
    }
313 314 315 316 317 318 319 320 321 322
    scratch = buffer->get_scratch_buffer (&scratch_size);
  }

#define ALLOCATE_ARRAY(Type, name, len) \
  Type *name = (Type *) scratch; \
  { \
    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
    assert (_consumed <= scratch_size); \
    scratch += _consumed; \
    scratch_size -= _consumed; \
323
  }
B
Behdad Esfahbod 已提交
324

325 326
  ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
  ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
B
Behdad Esfahbod 已提交
327

328 329
#undef ALLOCATE_ARRAY

330 331 332
  memset (clusters, 0, sizeof (clusters[0]) * buffer->len);

  hb_codepoint_t *pg = gids;
333
  clusters[0].cluster = buffer->info[0].cluster;
M
mhosken 已提交
334
  float curradv = 0.;
335 336 337 338 339
  if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
  {
    curradv = gr_slot_origin_X(gr_seg_first_slot(seg));
    clusters[0].advance = gr_seg_advance_X(seg) - curradv;
  }
340 341
  else
    clusters[0].advance = 0;
B
Behdad Esfahbod 已提交
342 343 344 345 346 347 348
  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)
349
    {
B
Behdad Esfahbod 已提交
350 351
      clusters[ci-1].num_chars += clusters[ci].num_chars;
      clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
352
      clusters[ci-1].advance += clusters[ci].advance;
B
Minor  
Behdad Esfahbod 已提交
353
      ci--;
354 355
    }

B
Behdad Esfahbod 已提交
356
    if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
357
    {
358
      hb_graphite2_cluster_t *c = clusters + ci + 1;
B
Behdad Esfahbod 已提交
359
      c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
360
      c->cluster = buffer->info[c->base_char].cluster;
B
Behdad Esfahbod 已提交
361 362 363
      c->num_chars = before - c->base_char;
      c->base_glyph = ic;
      c->num_glyphs = 0;
364
      if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
M
mhosken 已提交
365 366
        c->advance = curradv - gr_slot_origin_X(is);
      else
367 368 369 370
      {
        c->advance = 0;
        clusters[ci].advance += gr_slot_origin_X(is) - curradv;
      }
M
mhosken 已提交
371
      ci++;
372
      curradv = gr_slot_origin_X(is);
373
    }
B
Minor  
Behdad Esfahbod 已提交
374
    clusters[ci].num_glyphs++;
B
Behdad Esfahbod 已提交
375 376 377 378

    if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
	clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
  }
379

M
mhosken 已提交
380 381 382
  if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
    clusters[ci].advance += curradv;
  else
383
    clusters[ci].advance += gr_seg_advance_X(seg) - curradv;
B
Minor  
Behdad Esfahbod 已提交
384
  ci++;
B
Behdad Esfahbod 已提交
385

B
Minor  
Behdad Esfahbod 已提交
386
  for (unsigned int i = 0; i < ci; ++i)
B
Behdad Esfahbod 已提交
387 388 389 390 391
  {
    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];
392
      info->cluster = clusters[i].cluster;
393
      info->var1.i32 = clusters[i].advance;     // all glyphs in the cluster get the same advance
B
Behdad Esfahbod 已提交
394 395 396
    }
  }
  buffer->len = glyph_count;
B
Behdad Esfahbod 已提交
397

398 399 400 401
  unsigned int upem = hb_face_get_upem (face);
  float xscale = (float) font->x_scale / upem;
  float yscale = (float) font->y_scale / upem;
  yscale *= yscale / xscale;
B
Behdad Esfahbod 已提交
402
  /* Positioning. */
B
Behdad Esfahbod 已提交
403
  unsigned int currclus = (unsigned int) -1;
M
mhosken 已提交
404
  const hb_glyph_info_t *info = buffer->info;
B
Behdad Esfahbod 已提交
405
  hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr);
B
Behdad Esfahbod 已提交
406
  if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
B
Behdad Esfahbod 已提交
407
  {
408 409
    curradvx = 0;
    for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
B
Behdad Esfahbod 已提交
410
    {
411
      pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
M
Martin Hosken 已提交
412
      pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
413
      if (info->cluster != currclus) {
414 415 416
	pPos->x_advance = info->var1.i32 * xscale;
	curradvx += pPos->x_advance;
	currclus = info->cluster;
417
      } else
418
	pPos->x_advance = 0.;
419

B
Behdad Esfahbod 已提交
420
      pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
B
Behdad Esfahbod 已提交
421 422 423 424 425
      curradvy += pPos->y_advance;
    }
  }
  else
  {
426
    curradvx = gr_seg_advance_X(seg) * xscale;
427
    for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
B
Behdad Esfahbod 已提交
428 429 430
    {
      if (info->cluster != currclus)
      {
431 432 433
	pPos->x_advance = info->var1.i32 * xscale;
	curradvx -= pPos->x_advance;
	currclus = info->cluster;
434
      } else
435
	pPos->x_advance = 0.;
436

B
Behdad Esfahbod 已提交
437
      pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
B
Behdad Esfahbod 已提交
438
      curradvy -= pPos->y_advance;
M
mhosken 已提交
439
      pPos->x_offset = (gr_slot_origin_X (is) - info->var1.i32) * xscale - curradvx + pPos->x_advance;
M
Martin Hosken 已提交
440
      pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
B
Behdad Esfahbod 已提交
441
    }
442
    hb_buffer_reverse_clusters (buffer);
B
Behdad Esfahbod 已提交
443
  }
444

B
Behdad Esfahbod 已提交
445
  if (feats) gr_featureval_destroy (feats);
446 447
  gr_seg_destroy (seg);

448 449
  buffer->unsafe_to_break_all ();

450
  return true;
451
}