tor-browser

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

MarkMarkPosFormat1.hh (8341B)


      1 #ifndef OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
      2 #define OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
      3 
      4 #include "MarkMarkPosFormat1.hh"
      5 
      6 namespace OT {
      7 namespace Layout {
      8 namespace GPOS_impl {
      9 
     10 typedef AnchorMatrix Mark2Array;        /* mark2-major--
     11                                         * in order of Mark2Coverage Index--,
     12                                         * mark1-minor--
     13                                         * ordered by class--zero-based. */
     14 
     15 template <typename Types>
     16 struct MarkMarkPosFormat1_2
     17 {
     18  protected:
     19  HBUINT16      format;                 /* Format identifier--format = 1 */
     20  typename Types::template OffsetTo<Coverage>
     21                mark1Coverage;          /* Offset to Combining Mark1 Coverage
     22                                         * table--from beginning of MarkMarkPos
     23                                         * subtable */
     24  typename Types::template OffsetTo<Coverage>
     25                mark2Coverage;          /* Offset to Combining Mark2 Coverage
     26                                         * table--from beginning of MarkMarkPos
     27                                         * subtable */
     28  HBUINT16      classCount;             /* Number of defined mark classes */
     29  typename Types::template OffsetTo<MarkArray>
     30                mark1Array;             /* Offset to Mark1Array table--from
     31                                         * beginning of MarkMarkPos subtable */
     32  typename Types::template OffsetTo<Mark2Array>
     33                mark2Array;             /* Offset to Mark2Array table--from
     34                                         * beginning of MarkMarkPos subtable */
     35  public:
     36  DEFINE_SIZE_STATIC (4 + 4 * Types::size);
     37 
     38  bool sanitize (hb_sanitize_context_t *c) const
     39  {
     40    TRACE_SANITIZE (this);
     41    return_trace (c->check_struct (this) &&
     42                  mark1Coverage.sanitize (c, this) &&
     43                  mark2Coverage.sanitize (c, this) &&
     44                  mark1Array.sanitize (c, this) &&
     45 	  hb_barrier () &&
     46                  mark2Array.sanitize (c, this, (unsigned int) classCount));
     47  }
     48 
     49  bool intersects (const hb_set_t *glyphs) const
     50  {
     51    return (this+mark1Coverage).intersects (glyphs) &&
     52           (this+mark2Coverage).intersects (glyphs);
     53  }
     54 
     55  void closure_lookups (hb_closure_lookups_context_t *c) const {}
     56 
     57  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
     58  {
     59    + hb_zip (this+mark1Coverage, this+mark1Array)
     60    | hb_filter (c->glyph_set, hb_first)
     61    | hb_map (hb_second)
     62    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); })
     63    ;
     64 
     65    hb_map_t klass_mapping;
     66    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);
     67 
     68    unsigned mark2_count = (this+mark2Array).rows;
     69    auto mark2_iter =
     70    + hb_zip (this+mark2Coverage, hb_range (mark2_count))
     71    | hb_filter (c->glyph_set, hb_first)
     72    | hb_map (hb_second)
     73    ;
     74 
     75    hb_sorted_vector_t<unsigned> mark2_indexes;
     76    for (const unsigned row : mark2_iter)
     77    {
     78      + hb_range ((unsigned) classCount)
     79      | hb_filter (klass_mapping)
     80      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
     81      | hb_sink (mark2_indexes)
     82      ;
     83    }
     84    (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
     85  }
     86 
     87  void collect_glyphs (hb_collect_glyphs_context_t *c) const
     88  {
     89    if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
     90    if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
     91  }
     92 
     93  const Coverage &get_coverage () const { return this+mark1Coverage; }
     94 
     95  bool apply (hb_ot_apply_context_t *c) const
     96  {
     97    TRACE_APPLY (this);
     98    hb_buffer_t *buffer = c->buffer;
     99    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
    100    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
    101 
    102    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
    103    auto &skippy_iter = c->iter_input;
    104    skippy_iter.reset_fast (buffer->idx);
    105    skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
    106    unsigned unsafe_from;
    107    if (unlikely (!skippy_iter.prev (&unsafe_from)))
    108    {
    109      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
    110      return_trace (false);
    111    }
    112 
    113    if (likely (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])))
    114    {
    115      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
    116      return_trace (false);
    117    }
    118 
    119    unsigned int j = skippy_iter.idx;
    120 
    121    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
    122    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
    123    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
    124    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
    125 
    126    if (likely (id1 == id2))
    127    {
    128      if (id1 == 0) /* Marks belonging to the same base. */
    129        goto good;
    130      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
    131        goto good;
    132    }
    133    else
    134    {
    135      /* If ligature ids don't match, it may be the case that one of the marks
    136       * itself is a ligature.  In which case match. */
    137      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
    138        goto good;
    139    }
    140 
    141    /* Didn't match. */
    142    buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
    143    return_trace (false);
    144 
    145    good:
    146    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
    147    if (mark2_index == NOT_COVERED)
    148    {
    149      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
    150      return_trace (false);
    151    }
    152 
    153    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
    154  }
    155 
    156  bool subset (hb_subset_context_t *c) const
    157  {
    158    TRACE_SUBSET (this);
    159    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
    160    const hb_map_t &glyph_map = *c->plan->glyph_map;
    161 
    162    auto *out = c->serializer->start_embed (*this);
    163    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    164    out->format = format;
    165 
    166    hb_map_t klass_mapping;
    167    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);
    168 
    169    if (!klass_mapping.get_population ()) return_trace (false);
    170    out->classCount = klass_mapping.get_population ();
    171 
    172    auto mark1_iter =
    173    + hb_zip (this+mark1Coverage, this+mark1Array)
    174    | hb_filter (glyphset, hb_first)
    175    ;
    176 
    177    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
    178    + mark1_iter
    179    | hb_map (hb_first)
    180    | hb_map (glyph_map)
    181    | hb_sink (new_coverage)
    182    ;
    183 
    184    if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
    185      return_trace (false);
    186 
    187    if (unlikely (!out->mark1Array.serialize_subset (c, mark1Array, this,
    188 					     (this+mark1Coverage).iter (),
    189 					     &klass_mapping)))
    190      return_trace (false);
    191 
    192    unsigned mark2count = (this+mark2Array).rows;
    193    auto mark2_iter =
    194    + hb_zip (this+mark2Coverage, hb_range (mark2count))
    195    | hb_filter (glyphset, hb_first)
    196    ;
    197 
    198    new_coverage.reset ();
    199    hb_sorted_vector_t<unsigned> mark2_indexes;
    200    auto &mark2_array = (this+mark2Array);
    201    for (const auto _ : + mark2_iter)
    202    {
    203      unsigned row = _.second;
    204 
    205      bool non_empty = + hb_range ((unsigned) classCount)
    206                       | hb_filter (klass_mapping)
    207                       | hb_map ([&] (const unsigned col) { return !mark2_array.offset_is_null (row, col, (unsigned) classCount); })
    208                       | hb_any
    209                       ;
    210 
    211      if (!non_empty) continue;
    212 
    213      hb_codepoint_t new_g = glyph_map.get ( _.first);
    214      new_coverage.push (new_g);
    215 
    216      + hb_range ((unsigned) classCount)
    217      | hb_filter (klass_mapping)
    218      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
    219      | hb_sink (mark2_indexes)
    220      ;
    221    }
    222 
    223    if (!new_coverage) return_trace (false);
    224    if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
    225      return_trace (false);
    226 
    227    return_trace (out->mark2Array.serialize_subset (c, mark2Array, this,
    228 					    mark2_iter.len (),
    229 					    mark2_indexes.iter ()));
    230 
    231  }
    232 };
    233 
    234 
    235 }
    236 }
    237 }
    238 
    239 #endif /* OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH */