tor-browser

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

Glyph.hh (18279B)


      1 #ifndef OT_GLYF_GLYPH_HH
      2 #define OT_GLYF_GLYPH_HH
      3 
      4 
      5 #include "../../hb-open-type.hh"
      6 
      7 #include "GlyphHeader.hh"
      8 #include "SimpleGlyph.hh"
      9 #include "CompositeGlyph.hh"
     10 
     11 
     12 namespace OT {
     13 
     14 struct glyf_accelerator_t;
     15 
     16 namespace glyf_impl {
     17 
     18 
     19 enum phantom_point_index_t
     20 {
     21  PHANTOM_LEFT   = 0,
     22  PHANTOM_RIGHT  = 1,
     23  PHANTOM_TOP    = 2,
     24  PHANTOM_BOTTOM = 3,
     25  PHANTOM_COUNT  = 4
     26 };
     27 
     28 struct Glyph
     29 {
     30  enum glyph_type_t {
     31    EMPTY,
     32    SIMPLE,
     33    COMPOSITE,
     34  };
     35 
     36  public:
     37  composite_iter_t get_composite_iterator () const
     38  {
     39    if (type != COMPOSITE) return composite_iter_t ();
     40    return CompositeGlyph (*header, bytes).iter ();
     41  }
     42 
     43  const hb_bytes_t trim_padding () const
     44  {
     45    switch (type) {
     46    case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
     47    case SIMPLE:    return SimpleGlyph (*header, bytes).trim_padding ();
     48    case EMPTY:     return bytes;
     49    default:        return bytes;
     50    }
     51  }
     52 
     53  void drop_hints ()
     54  {
     55    switch (type) {
     56    case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
     57    case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints (); return;
     58    case EMPTY:     return;
     59    }
     60  }
     61 
     62  void set_overlaps_flag ()
     63  {
     64    switch (type) {
     65    case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
     66    case SIMPLE:    SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
     67    case EMPTY:     return;
     68    }
     69  }
     70 
     71  void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
     72  {
     73    switch (type) {
     74    case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
     75    case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
     76    case EMPTY:     return;
     77    }
     78  }
     79 
     80  bool is_composite () const
     81  { return type == COMPOSITE; }
     82 
     83  bool get_all_points_without_var (const hb_face_t *face,
     84                                   contour_point_vector_t &points /* OUT */) const
     85  {
     86    switch (type) {
     87    case SIMPLE:
     88      if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points)))
     89        return false;
     90      break;
     91    case COMPOSITE:
     92    {
     93      for (auto &item : get_composite_iterator ())
     94        if (unlikely (!item.get_points (points))) return false;
     95      break;
     96    }
     97    case EMPTY:
     98      break;
     99    }
    100 
    101    /* Init phantom points */
    102    if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
    103    hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
    104    {
    105      // Duplicated code.
    106      int lsb = 0;
    107      face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
    108      int h_delta = (int) header->xMin - lsb;
    109      HB_UNUSED int tsb = 0;
    110 #ifndef HB_NO_VERTICAL
    111      face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb);
    112 #endif
    113      int v_orig  = (int) header->yMax + tsb;
    114      unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid);
    115      unsigned v_adv =
    116 #ifndef HB_NO_VERTICAL
    117                       face->table.vmtx->get_advance_without_var_unscaled (gid)
    118 #else
    119                       - face->get_upem ()
    120 #endif
    121                       ;
    122      phantoms[PHANTOM_LEFT].x = h_delta;
    123      phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
    124      phantoms[PHANTOM_TOP].y = v_orig;
    125      phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
    126    }
    127    return true;
    128  }
    129 
    130  void update_mtx (const hb_subset_plan_t *plan,
    131                   int xMin, int xMax,
    132                   int yMin, int yMax,
    133                   const contour_point_vector_t &all_points) const
    134  {
    135    hb_codepoint_t new_gid = 0;
    136    if (!plan->new_gid_for_old_gid (gid, &new_gid))
    137      return;
    138 
    139    if (type != EMPTY)
    140    {
    141      plan->bounds_width_vec[new_gid] = xMax - xMin;
    142      plan->bounds_height_vec[new_gid] = yMax - yMin;
    143    }
    144 
    145    unsigned len = all_points.length;
    146    float leftSideX = all_points[len - 4].x;
    147    float rightSideX = all_points[len - 3].x;
    148    float topSideY = all_points[len - 2].y;
    149    float bottomSideY = all_points[len - 1].y;
    150 
    151    uint32_t hash = hb_hash (new_gid);
    152 
    153    signed hori_aw = roundf (rightSideX - leftSideX);
    154    if (hori_aw < 0) hori_aw = 0;
    155    int lsb = roundf (xMin - leftSideX);
    156    plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb));
    157    //flag value should be computed using non-empty glyphs
    158    if (type != EMPTY && lsb != xMin)
    159      plan->head_maxp_info.allXMinIsLsb = false;
    160 
    161    signed vert_aw = roundf (topSideY - bottomSideY);
    162    if (vert_aw < 0) vert_aw = 0;
    163    int tsb = roundf (topSideY - yMax);
    164    plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb));
    165  }
    166 
    167  bool compile_header_bytes (const hb_subset_plan_t *plan,
    168                             const contour_point_vector_t &all_points,
    169                             hb_bytes_t &dest_bytes /* OUT */) const
    170  {
    171    GlyphHeader *glyph_header = nullptr;
    172    if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4)
    173    {
    174      glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
    175      if (unlikely (!glyph_header)) return false;
    176    }
    177 
    178    float xMin = 0, xMax = 0;
    179    float yMin = 0, yMax = 0;
    180    if (all_points.length > 4)
    181    {
    182      xMin = xMax = all_points[0].x;
    183      yMin = yMax = all_points[0].y;
    184 
    185      unsigned count = all_points.length - 4;
    186      for (unsigned i = 1; i < count; i++)
    187      {
    188 float x = all_points[i].x;
    189 float y = all_points[i].y;
    190 xMin = hb_min (xMin, x);
    191 xMax = hb_max (xMax, x);
    192 yMin = hb_min (yMin, y);
    193 yMax = hb_max (yMax, y);
    194      }
    195    }
    196 
    197 
    198    // These are destined for storage in a 16 bit field to clamp the values to
    199    // fit into a 16 bit signed integer.
    200    int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f);
    201    int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f);
    202    int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f);
    203    int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f);
    204 
    205    update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points);
    206 
    207    if (type != EMPTY)
    208    {
    209      plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin);
    210      plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin);
    211      plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax);
    212      plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax);
    213    }
    214 
    215    /* when pinned at default, no need to compile glyph header
    216     * and for empty glyphs: all_points only include phantom points.
    217     * just update metrics and then return */
    218    if (!glyph_header)
    219      return true;
    220 
    221    glyph_header->numberOfContours = header->numberOfContours;
    222 
    223    glyph_header->xMin = rounded_xMin;
    224    glyph_header->yMin = rounded_yMin;
    225    glyph_header->xMax = rounded_xMax;
    226    glyph_header->yMax = rounded_yMax;
    227 
    228    dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
    229    return true;
    230  }
    231 
    232  bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
    233                                  hb_font_t *font,
    234                                  const glyf_accelerator_t &glyf,
    235                                  hb_bytes_t &dest_start,  /* IN/OUT */
    236                                  hb_bytes_t &dest_end /* OUT */)
    237  {
    238    contour_point_vector_t all_points, points_with_deltas;
    239    unsigned composite_contours = 0;
    240    head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
    241    unsigned *composite_contours_p = &composite_contours;
    242 
    243    // don't compute head/maxp values when glyph has no contours(type is EMPTY)
    244    // also ignore .notdef glyph when --notdef-outline is not enabled
    245    if (type == EMPTY ||
    246        (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)))
    247    {
    248      head_maxp_info_p = nullptr;
    249      composite_contours_p = nullptr;
    250    }
    251 
    252    hb_glyf_scratch_t scratch;
    253    if (!get_points (font, glyf, all_points, scratch, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
    254      return false;
    255 
    256    // .notdef, set type to empty so we only update metrics and don't compile bytes for
    257    // it
    258    if (gid == 0 &&
    259        !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
    260    {
    261      type = EMPTY;
    262      dest_start = hb_bytes_t ();
    263      dest_end = hb_bytes_t ();
    264    }
    265 
    266    //dont compile bytes when pinned at default, just recalculate bounds
    267    if (!plan->pinned_at_default)
    268    {
    269      switch (type)
    270      {
    271      case COMPOSITE:
    272        if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
    273                                                                        points_with_deltas,
    274                                                                        dest_end))
    275          return false;
    276        break;
    277      case SIMPLE:
    278        if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
    279                                                                     plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
    280                                                                     dest_end))
    281          return false;
    282        break;
    283      case EMPTY:
    284        /* set empty bytes for empty glyph
    285         * do not use source glyph's pointers */
    286        dest_start = hb_bytes_t ();
    287        dest_end = hb_bytes_t ();
    288        break;
    289      }
    290    }
    291 
    292    if (!compile_header_bytes (plan, all_points, dest_start))
    293    {
    294      dest_end.fini ();
    295      return false;
    296    }
    297    return true;
    298  }
    299 
    300 
    301  /* Note: Recursively calls itself.
    302   * all_points includes phantom points
    303   */
    304  template <typename accelerator_t>
    305  bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
    306 	   contour_point_vector_t &all_points /* OUT */,
    307 	   hb_glyf_scratch_t &scratch,
    308 	   contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
    309 	   head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
    310 	   unsigned *composite_contours = nullptr, /* OUT */
    311 	   bool shift_points_hori = true,
    312 	   bool use_my_metrics = true,
    313 	   bool phantom_only = false,
    314 	   hb_array_t<const int> coords = hb_array_t<const int> (),
    315 	   hb_scalar_cache_t *gvar_cache = nullptr,
    316 	   unsigned int depth = 0,
    317 	   unsigned *edge_count = nullptr) const
    318  {
    319    if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
    320    unsigned stack_edge_count = 0;
    321    if (!edge_count) edge_count = &stack_edge_count;
    322    if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false;
    323    (*edge_count)++;
    324 
    325    if (head_maxp_info)
    326    {
    327      head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
    328    }
    329 
    330    if (!coords && font->has_nonzero_coords)
    331      coords = hb_array (font->coords, font->num_coords);
    332 
    333    contour_point_vector_t &points = type == SIMPLE ? all_points : scratch.comp_points;
    334    unsigned old_length = points.length;
    335 
    336    switch (type) {
    337    case SIMPLE:
    338      if (depth == 0 && head_maxp_info)
    339        head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
    340      if (depth > 0 && composite_contours)
    341        *composite_contours += (unsigned) header->numberOfContours;
    342      if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only)))
    343 return false;
    344      break;
    345    case COMPOSITE:
    346    {
    347      for (auto &item : get_composite_iterator ())
    348        if (unlikely (!item.get_points (points))) return false;
    349      break;
    350    }
    351    case EMPTY:
    352      break;
    353    }
    354 
    355    /* Init phantom points */
    356    if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
    357    hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
    358    {
    359      // Duplicated code.
    360      int lsb = 0;
    361      glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
    362      int h_delta = (int) header->xMin - lsb;
    363      HB_UNUSED int tsb = 0;
    364 #ifndef HB_NO_VERTICAL
    365      glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb);
    366 #endif
    367      int v_orig  = (int) header->yMax + tsb;
    368      unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid);
    369      unsigned v_adv =
    370 #ifndef HB_NO_VERTICAL
    371                       glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid)
    372 #else
    373                       - font->face->get_upem ()
    374 #endif
    375                       ;
    376      phantoms[PHANTOM_LEFT].x = h_delta;
    377      phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
    378      phantoms[PHANTOM_TOP].y = v_orig;
    379      phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
    380    }
    381 
    382 #ifndef HB_NO_VAR
    383    if (hb_any (coords))
    384    {
    385 #ifndef HB_NO_BEYOND_64K
    386      if (glyf_accelerator.GVAR->has_data ())
    387 glyf_accelerator.GVAR->apply_deltas_to_points (gid,
    388 					       coords,
    389 					       points.as_array ().sub_array (old_length),
    390 					       scratch,
    391 					       gvar_cache,
    392 					       phantom_only && type == SIMPLE);
    393      else
    394 #endif
    395 glyf_accelerator.gvar->apply_deltas_to_points (gid,
    396 					       coords,
    397 					       points.as_array ().sub_array (old_length),
    398 					       scratch,
    399 					       gvar_cache,
    400 					       phantom_only && type == SIMPLE);
    401    }
    402 #endif
    403 
    404    // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
    405    // with child glyphs' points
    406    if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
    407    {
    408      assert (old_length == 0);
    409      *points_with_deltas = points;
    410    }
    411 
    412    float shift = 0;
    413    switch (type) {
    414    case SIMPLE:
    415      if (depth == 0 && head_maxp_info)
    416        head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
    417      shift = phantoms[PHANTOM_LEFT].x;
    418      break;
    419    case COMPOSITE:
    420    {
    421      hb_decycler_node_t decycler_node (scratch.decycler);
    422 
    423      unsigned int comp_index = 0;
    424      for (auto &item : get_composite_iterator ())
    425      {
    426 hb_codepoint_t item_gid = item.get_gid ();
    427 
    428        if (unlikely (!decycler_node.visit (item_gid)))
    429 {
    430   comp_index++;
    431   continue;
    432 }
    433 
    434 unsigned old_count = all_points.length;
    435 
    436 if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
    437 	      !glyf_accelerator.glyph_for_gid (item_gid)
    438 			       .get_points (font,
    439 					    glyf_accelerator,
    440 					    all_points,
    441 					    scratch,
    442 					    points_with_deltas,
    443 					    head_maxp_info,
    444 					    composite_contours,
    445 					    shift_points_hori,
    446 					    use_my_metrics,
    447 					    phantom_only,
    448 					    coords,
    449 					    gvar_cache,
    450 					    depth + 1,
    451 					    edge_count)))
    452 {
    453   points.resize (old_length);
    454   return false;
    455 }
    456 
    457 // points might have been reallocated. Relocate phantoms.
    458 phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
    459 
    460 auto comp_points = all_points.as_array ().sub_array (old_count);
    461 
    462 /* Copy phantom points from component if USE_MY_METRICS flag set */
    463 if (use_my_metrics && item.is_use_my_metrics ())
    464   for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
    465     phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
    466 
    467 if (comp_points) // Empty in case of phantom_only
    468 {
    469   float matrix[4];
    470   contour_point_t default_trans;
    471   item.get_transformation (matrix, default_trans);
    472 
    473   /* Apply component transformation & translation (with deltas applied) */
    474   item.transform_points (comp_points, matrix, points[old_length + comp_index]);
    475 }
    476 
    477 if (item.is_anchored () && !phantom_only)
    478 {
    479   unsigned int p1, p2;
    480   item.get_anchor_points (p1, p2);
    481   if (likely (p1 < all_points.length && p2 < comp_points.length))
    482   {
    483     contour_point_t delta;
    484     delta.init (all_points[p1].x - comp_points[p2].x,
    485 		all_points[p1].y - comp_points[p2].y);
    486 
    487     item.translate (delta, comp_points);
    488   }
    489 }
    490 
    491 all_points.resize (all_points.length - PHANTOM_COUNT);
    492 
    493 if (all_points.length > HB_GLYF_MAX_POINTS)
    494 {
    495   points.resize (old_length);
    496   return false;
    497 }
    498 
    499 comp_index++;
    500      }
    501 
    502      if (head_maxp_info && depth == 0)
    503      {
    504        if (composite_contours)
    505          head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours);
    506        head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length);
    507        head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
    508      }
    509      all_points.extend (phantoms);
    510      shift = phantoms[PHANTOM_LEFT].x;
    511      points.resize (old_length);
    512    } break;
    513    case EMPTY:
    514      all_points.extend (phantoms);
    515      shift = phantoms[PHANTOM_LEFT].x;
    516      points.resize (old_length);
    517      break;
    518    }
    519 
    520    if (depth == 0 && shift_points_hori) /* Apply at top level */
    521    {
    522      /* Undocumented rasterizer behavior:
    523       * Shift points horizontally by the updated left side bearing
    524       */
    525      if (shift)
    526        for (auto &point : all_points)
    527   point.x -= shift;
    528    }
    529 
    530    return !all_points.in_error ();
    531  }
    532 
    533  bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
    534 			       hb_glyph_extents_t *extents) const
    535  {
    536    if (type == EMPTY)
    537    {
    538      *extents = {0, 0, 0, 0};
    539      return true; /* Empty glyph; zero extents. */
    540    }
    541    return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
    542  }
    543 
    544  hb_bytes_t get_bytes () const { return bytes; }
    545  glyph_type_t get_type () const { return type; }
    546  const GlyphHeader *get_header () const { return header; }
    547 
    548  Glyph () : bytes (),
    549             header (bytes.as<GlyphHeader> ()),
    550             gid (-1),
    551             type(EMPTY)
    552  {}
    553 
    554  Glyph (hb_bytes_t bytes_,
    555  hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
    556                                                header (bytes.as<GlyphHeader> ()),
    557                                                gid (gid_)
    558  {
    559    int num_contours = header->numberOfContours;
    560    if (unlikely (num_contours == 0)) type = EMPTY;
    561    else if (num_contours > 0) type = SIMPLE;
    562    else if (num_contours <= -1) type = COMPOSITE;
    563    else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
    564  }
    565 
    566  protected:
    567  hb_bytes_t bytes;
    568  const GlyphHeader *header;
    569  hb_codepoint_t gid;
    570  glyph_type_t type;
    571 };
    572 
    573 
    574 } /* namespace glyf_impl */
    575 } /* namespace OT */
    576 
    577 
    578 #endif /* OT_GLYF_GLYPH_HH */