tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

shape.cc (7348B)


      1 #define HB_WASM_INTERFACE(ret_t, name) __attribute__((export_name(#name))) ret_t name
      2 
      3 #include <hb-wasm-api.h>
      4 
      5 #include <graphite2/Segment.h>
      6 
      7 #include <stdlib.h>
      8 #include <string.h>
      9 
     10 void debugprint1 (char *s, int32_t);
     11 void debugprint2 (char *s, int32_t, int32_t);
     12 
     13 static const void *copy_table (const void *data, unsigned int tag, size_t *len)
     14 {
     15  face_t *face = (face_t *) data;
     16  blob_t blob = BLOB_INIT;
     17  if (!face_copy_table (face, tag, &blob))
     18    abort ();
     19 
     20  *len = blob.length;
     21  return blob.data;
     22 }
     23 
     24 static void free_table (const void *data, const void *table_data)
     25 {
     26  blob_t blob;
     27  blob.length = 0; // Doesn't matter
     28  blob.data = (char *) table_data;
     29  blob_free (&blob);
     30 }
     31 
     32 void *
     33 shape_plan_create (face_t *face)
     34 {
     35  const gr_face_ops ops = {sizeof (gr_face_ops), &copy_table, &free_table};
     36  gr_face *grface = gr_make_face_with_ops (face, &ops, gr_face_preloadAll);
     37  return grface;
     38 }
     39 
     40 void
     41 shape_plan_destroy (void *data)
     42 {
     43  gr_face_destroy ((gr_face *) data);
     44 }
     45 
     46 bool_t
     47 shape (void *shape_plan,
     48       font_t *font,
     49       buffer_t *buffer,
     50       const feature_t *features,
     51       uint32_t num_features)
     52 {
     53  face_t *face = font_get_face (font);
     54  gr_face *grface = (gr_face *) shape_plan;
     55 
     56  direction_t direction = buffer_get_direction (buffer);
     57  direction_t horiz_dir = script_get_horizontal_direction (buffer_get_script (buffer));
     58  /* TODO vertical:
     59   * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
     60   * Ogham fonts are supposed to be implemented BTT or not.  Need to research that
     61   * first. */
     62  if ((DIRECTION_IS_HORIZONTAL (direction) &&
     63       direction != horiz_dir && horiz_dir != DIRECTION_INVALID) ||
     64      (DIRECTION_IS_VERTICAL   (direction) &&
     65       direction != DIRECTION_TTB))
     66  {
     67    buffer_reverse_clusters (buffer);
     68    direction = DIRECTION_REVERSE (direction);
     69  }
     70 
     71  buffer_contents_t contents = BUFFER_CONTENTS_INIT;
     72  if (!buffer_copy_contents (buffer, &contents))
     73    return false;
     74 
     75  gr_segment *seg = nullptr;
     76  const gr_slot *is;
     77  unsigned int ci = 0, ic = 0;
     78  unsigned int curradvx = 0, curradvy = 0;
     79  unsigned length = contents.length;
     80 
     81  uint32_t *chars = (uint32_t *) malloc (length * sizeof (uint32_t));
     82  if (!chars)
     83    return false;
     84  for (unsigned int i = 0; i < contents.length; ++i)
     85    chars[i] = contents.info[i].codepoint;
     86 
     87  seg = gr_make_seg (nullptr, grface,
     88 	     0, // https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148
     89 	     nullptr,
     90 	     gr_utf32, chars, contents.length,
     91 	     2 | (direction == DIRECTION_RTL ? 1 : 0));
     92 
     93  free (chars);
     94 
     95  if (!seg)
     96    return false;
     97 
     98  unsigned int glyph_count = gr_seg_n_slots (seg);
     99 
    100  struct cluster_t {
    101    unsigned int base_char;
    102    unsigned int num_chars;
    103    unsigned int base_glyph;
    104    unsigned int num_glyphs;
    105    unsigned int cluster;
    106    int advance;
    107  };
    108 
    109  length = glyph_count;
    110  if (!buffer_contents_realloc (&contents, length))
    111    return false;
    112  cluster_t *clusters = (cluster_t *) malloc (length * sizeof (cluster_t));
    113  uint32_t *gids = (uint32_t *) malloc (length * sizeof (uint32_t));
    114  if (!clusters || !gids)
    115  {
    116    free (clusters);
    117    free (gids);
    118    return false;
    119  }
    120 
    121  memset (clusters, 0, sizeof (clusters[0]) * length);
    122  codepoint_t *pg = gids;
    123  clusters[0].cluster = contents.info[0].cluster;
    124  unsigned int upem = face_get_upem (face);
    125  int32_t font_x_scale, font_y_scale;
    126  font_get_scale (font, &font_x_scale, &font_y_scale);
    127  float xscale = (float) font_x_scale / upem;
    128  float yscale = (float) font_y_scale / upem;
    129  yscale *= yscale / xscale;
    130  unsigned int curradv = 0;
    131  if (DIRECTION_IS_BACKWARD (direction))
    132  {
    133    curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
    134    clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
    135  }
    136  else
    137    clusters[0].advance = 0;
    138  for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
    139  {
    140    unsigned int before = gr_slot_before (is);
    141    unsigned int after = gr_slot_after (is);
    142    *pg = gr_slot_gid (is);
    143    pg++;
    144    while (clusters[ci].base_char > before && ci)
    145    {
    146      clusters[ci-1].num_chars += clusters[ci].num_chars;
    147      clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
    148      clusters[ci-1].advance += clusters[ci].advance;
    149      ci--;
    150    }
    151 
    152    if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
    153    {
    154      cluster_t *c = clusters + ci + 1;
    155      c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
    156      c->cluster = contents.info[c->base_char].cluster;
    157      c->num_chars = before - c->base_char;
    158      c->base_glyph = ic;
    159      c->num_glyphs = 0;
    160      if (DIRECTION_IS_BACKWARD (direction))
    161      {
    162 c->advance = curradv - gr_slot_origin_X(is) * xscale;
    163 curradv -= c->advance;
    164      }
    165      else
    166      {
    167 auto origin_X = gr_slot_origin_X (is) * xscale;
    168 c->advance = 0;
    169 clusters[ci].advance += origin_X - curradv;
    170 curradv = origin_X;
    171      }
    172      ci++;
    173    }
    174    clusters[ci].num_glyphs++;
    175 
    176    if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
    177 clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
    178  }
    179 
    180  if (DIRECTION_IS_BACKWARD (direction))
    181    clusters[ci].advance += curradv;
    182  else
    183    clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
    184  ci++;
    185 
    186  for (unsigned int i = 0; i < ci; ++i)
    187  {
    188    for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
    189    {
    190      glyph_info_t *info = &contents.info[clusters[i].base_glyph + j];
    191      info->codepoint = gids[clusters[i].base_glyph + j];
    192      info->cluster = clusters[i].cluster;
    193      info->var1 = (unsigned) clusters[i].advance;     // all glyphs in the cluster get the same advance
    194    }
    195  }
    196  contents.length = glyph_count;
    197 
    198  /* Positioning. */
    199  unsigned int currclus = 0xFFFFFFFF;
    200  const glyph_info_t *info = contents.info;
    201  glyph_position_t *pPos = contents.pos;
    202  if (!DIRECTION_IS_BACKWARD (direction))
    203  {
    204    curradvx = 0;
    205    for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
    206    {
    207      pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
    208      pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
    209      if (info->cluster != currclus) {
    210 pPos->x_advance = (int) info->var1;
    211 curradvx += pPos->x_advance;
    212 currclus = info->cluster;
    213      } else
    214 pPos->x_advance = 0.;
    215 
    216      pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
    217      curradvy += pPos->y_advance;
    218    }
    219    buffer_set_contents (buffer, &contents);
    220  }
    221  else
    222  {
    223    curradvx = gr_seg_advance_X(seg) * xscale;
    224    for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
    225    {
    226      if (info->cluster != currclus)
    227      {
    228 pPos->x_advance = (int) info->var1;
    229 curradvx -= pPos->x_advance;
    230 currclus = info->cluster;
    231      } else
    232 pPos->x_advance = 0.;
    233 
    234      pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
    235      curradvy -= pPos->y_advance;
    236      pPos->x_offset = gr_slot_origin_X (is) * xscale - (int) info->var1 - curradvx + pPos->x_advance;
    237      pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
    238    }
    239    buffer_set_contents (buffer, &contents);
    240    buffer_reverse_clusters (buffer);
    241  }
    242 
    243  gr_seg_destroy (seg);
    244  free (clusters);
    245  free (gids);
    246 
    247  bool ret = glyph_count;
    248 
    249  return ret;
    250 }