tor-browser

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

CursivePosFormat1.hh (9986B)


      1 #ifndef OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH
      2 #define OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH
      3 
      4 #include "Anchor.hh"
      5 
      6 namespace OT {
      7 namespace Layout {
      8 namespace GPOS_impl {
      9 
     10 struct EntryExitRecord
     11 {
     12  friend struct CursivePosFormat1;
     13 
     14  bool sanitize (hb_sanitize_context_t *c, const struct CursivePosFormat1 *base) const
     15  {
     16    TRACE_SANITIZE (this);
     17    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
     18  }
     19 
     20  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
     21                                  const struct CursivePosFormat1 *src_base) const
     22  {
     23    (src_base+entryAnchor).collect_variation_indices (c);
     24    (src_base+exitAnchor).collect_variation_indices (c);
     25  }
     26 
     27  bool subset (hb_subset_context_t *c,
     28        const struct CursivePosFormat1 *src_base) const
     29  {
     30    TRACE_SERIALIZE (this);
     31    auto *out = c->serializer->embed (this);
     32    if (unlikely (!out)) return_trace (false);
     33 
     34    bool ret = false;
     35    ret |= out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
     36    ret |= out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
     37    return_trace (ret);
     38  }
     39 
     40  protected:
     41  Offset16To<Anchor, struct CursivePosFormat1>
     42                entryAnchor;            /* Offset to EntryAnchor table--from
     43                                         * beginning of CursivePos
     44                                         * subtable--may be NULL */
     45  Offset16To<Anchor, struct CursivePosFormat1>
     46                exitAnchor;             /* Offset to ExitAnchor table--from
     47                                         * beginning of CursivePos
     48                                         * subtable--may be NULL */
     49  public:
     50  DEFINE_SIZE_STATIC (4);
     51 };
     52 
     53 static inline void
     54 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
     55 {
     56  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
     57  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
     58    return;
     59 
     60  pos[i].attach_chain() = 0;
     61 
     62  unsigned int j = (int) i + chain;
     63 
     64  /* Stop if we see new parent in the chain. */
     65  if (j == new_parent)
     66    return;
     67 
     68  reverse_cursive_minor_offset (pos, j, direction, new_parent);
     69 
     70  if (HB_DIRECTION_IS_HORIZONTAL (direction))
     71    pos[j].y_offset = -pos[i].y_offset;
     72  else
     73    pos[j].x_offset = -pos[i].x_offset;
     74 
     75  pos[j].attach_chain() = -chain;
     76  pos[j].attach_type() = type;
     77 }
     78 
     79 
     80 struct CursivePosFormat1
     81 {
     82  protected:
     83  HBUINT16      format;                 /* Format identifier--format = 1 */
     84  Offset16To<Coverage>
     85                coverage;               /* Offset to Coverage table--from
     86                                         * beginning of subtable */
     87  Array16Of<EntryExitRecord>
     88                entryExitRecord;        /* Array of EntryExit records--in
     89                                         * Coverage Index order */
     90  public:
     91  DEFINE_SIZE_ARRAY (6, entryExitRecord);
     92 
     93  bool sanitize (hb_sanitize_context_t *c) const
     94  {
     95    TRACE_SANITIZE (this);
     96    if (unlikely (!coverage.sanitize (c, this)))
     97      return_trace (false);
     98 
     99    if (c->lazy_some_gpos)
    100      return_trace (entryExitRecord.sanitize_shallow (c));
    101    else
    102      return_trace (entryExitRecord.sanitize (c, this));
    103  }
    104 
    105  bool intersects (const hb_set_t *glyphs) const
    106  { return (this+coverage).intersects (glyphs); }
    107 
    108  void closure_lookups (hb_closure_lookups_context_t *c) const {}
    109 
    110  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
    111  {
    112    + hb_zip (this+coverage, entryExitRecord)
    113    | hb_filter (c->glyph_set, hb_first)
    114    | hb_map (hb_second)
    115    | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); })
    116    ;
    117  }
    118 
    119  void collect_glyphs (hb_collect_glyphs_context_t *c) const
    120  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
    121 
    122  const Coverage &get_coverage () const { return this+coverage; }
    123 
    124  bool apply (hb_ot_apply_context_t *c) const
    125  {
    126    TRACE_APPLY (this);
    127    hb_buffer_t *buffer = c->buffer;
    128 
    129    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
    130    if (!this_record.entryAnchor ||
    131 unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false);
    132    hb_barrier ();
    133 
    134    auto &skippy_iter = c->iter_input;
    135    skippy_iter.reset_fast (buffer->idx);
    136    unsigned unsafe_from;
    137    if (unlikely (!skippy_iter.prev (&unsafe_from)))
    138    {
    139      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
    140      return_trace (false);
    141    }
    142 
    143    const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
    144    if (!prev_record.exitAnchor ||
    145 unlikely (!prev_record.exitAnchor.sanitize (&c->sanitizer, this)))
    146    {
    147      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
    148      return_trace (false);
    149    }
    150    hb_barrier ();
    151 
    152    unsigned int i = skippy_iter.idx;
    153    unsigned int j = buffer->idx;
    154 
    155    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
    156    {
    157      c->buffer->message (c->font,
    158 		  "cursive attaching glyph at %u to glyph at %u",
    159 		  i, j);
    160    }
    161 
    162    buffer->unsafe_to_break (i, j + 1);
    163    float entry_x, entry_y, exit_x, exit_y;
    164    (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
    165    (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
    166 
    167    hb_glyph_position_t *pos = buffer->pos;
    168 
    169    hb_position_t d;
    170    /* Main-direction adjustment */
    171    switch (c->direction) {
    172      case HB_DIRECTION_LTR:
    173        pos[i].x_advance  = roundf (exit_x) + pos[i].x_offset;
    174 
    175        d = roundf (entry_x) + pos[j].x_offset;
    176        pos[j].x_advance -= d;
    177        pos[j].x_offset  -= d;
    178        break;
    179      case HB_DIRECTION_RTL:
    180        d = roundf (exit_x) + pos[i].x_offset;
    181        pos[i].x_advance -= d;
    182        pos[i].x_offset  -= d;
    183 
    184        pos[j].x_advance  = roundf (entry_x) + pos[j].x_offset;
    185        break;
    186      case HB_DIRECTION_TTB:
    187        pos[i].y_advance  = roundf (exit_y) + pos[i].y_offset;
    188 
    189        d = roundf (entry_y) + pos[j].y_offset;
    190        pos[j].y_advance -= d;
    191        pos[j].y_offset  -= d;
    192        break;
    193      case HB_DIRECTION_BTT:
    194        d = roundf (exit_y) + pos[i].y_offset;
    195        pos[i].y_advance -= d;
    196        pos[i].y_offset  -= d;
    197 
    198        pos[j].y_advance  = roundf (entry_y);
    199        break;
    200      case HB_DIRECTION_INVALID:
    201      default:
    202        break;
    203    }
    204 
    205    /* Cross-direction adjustment */
    206 
    207    /* We attach child to parent (think graph theory and rooted trees whereas
    208     * the root stays on baseline and each node aligns itself against its
    209     * parent.
    210     *
    211     * Optimize things for the case of RightToLeft, as that's most common in
    212     * Arabic. */
    213    unsigned int child  = i;
    214    unsigned int parent = j;
    215    hb_position_t x_offset = roundf (entry_x - exit_x);
    216    hb_position_t y_offset = roundf (entry_y - exit_y);
    217    if  (!(c->lookup_props & LookupFlag::RightToLeft))
    218    {
    219      unsigned int k = child;
    220      child = parent;
    221      parent = k;
    222      x_offset = -x_offset;
    223      y_offset = -y_offset;
    224    }
    225 
    226    /* If child was already connected to someone else, walk through its old
    227     * chain and reverse the link direction, such that the whole tree of its
    228     * previous connection now attaches to new parent.  Watch out for case
    229     * where new parent is on the path from old chain...
    230     */
    231    reverse_cursive_minor_offset (pos, child, c->direction, parent);
    232 
    233    pos[child].attach_chain() = (int) parent - (int) child;
    234    if (pos[child].attach_chain() != (int) parent - (int) child)
    235    {
    236      pos[child].attach_chain() = 0;
    237      goto overflow;
    238    }
    239    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
    240    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
    241    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
    242      pos[child].y_offset = y_offset;
    243    else
    244      pos[child].x_offset = x_offset;
    245 
    246    /* If parent was attached to child, separate them.
    247     * https://github.com/harfbuzz/harfbuzz/issues/2469
    248     */
    249    if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
    250    {
    251      pos[parent].attach_chain() = 0;
    252      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
    253 pos[parent].y_offset = 0;
    254      else
    255 pos[parent].x_offset = 0;
    256    }
    257 
    258    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
    259    {
    260      c->buffer->message (c->font,
    261 		  "cursive attached glyph at %u to glyph at %u",
    262 		  i, j);
    263    }
    264 
    265  overflow:
    266    buffer->idx++;
    267    return_trace (true);
    268  }
    269 
    270  template <typename Iterator,
    271            hb_requires (hb_is_iterator (Iterator))>
    272  void serialize (hb_subset_context_t *c,
    273                  Iterator it,
    274                  const struct CursivePosFormat1 *src_base)
    275  {
    276    if (unlikely (!c->serializer->extend_min ((*this)))) return;
    277    this->format = 1;
    278    this->entryExitRecord.len = it.len ();
    279 
    280    for (const EntryExitRecord& entry_record : + it
    281                                               | hb_map (hb_second))
    282      entry_record.subset (c, src_base);
    283 
    284    auto glyphs =
    285    + it
    286    | hb_map_retains_sorting (hb_first)
    287    ;
    288 
    289    coverage.serialize_serialize (c->serializer, glyphs);
    290  }
    291 
    292  bool subset (hb_subset_context_t *c) const
    293  {
    294    TRACE_SUBSET (this);
    295    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
    296    const hb_map_t &glyph_map = *c->plan->glyph_map;
    297 
    298    auto *out = c->serializer->start_embed (*this);
    299 
    300    auto it =
    301    + hb_zip (this+coverage, entryExitRecord)
    302    | hb_filter (glyphset, hb_first)
    303    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
    304                              { return hb_pair (glyph_map[p.first], p.second);})
    305    ;
    306 
    307    bool ret = bool (it);
    308    out->serialize (c, it, this);
    309    return_trace (ret);
    310  }
    311 };
    312 
    313 
    314 }
    315 }
    316 }
    317 
    318 #endif /* OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH */