Coverage Report

Created: 2026-08-14 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
Line
Count
Source
1
#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH
2
#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH
3
4
#include "Common.hh"
5
#include "ValueFormat.hh"
6
7
namespace OT {
8
namespace Layout {
9
namespace GPOS_impl {
10
11
struct SinglePosFormat1 : ValueBase
12
{
13
  protected:
14
  HBUINT16      format;                 /* Format identifier--format = 1 */
15
  Offset16To<Coverage>
16
                coverage;               /* Offset to Coverage table--from
17
                                         * beginning of subtable */
18
  ValueFormat   valueFormat;            /* Defines the types of data in the
19
                                         * ValueRecord */
20
  ValueRecord   values;                 /* Defines positioning
21
                                         * value(s)--applied to all glyphs in
22
                                         * the Coverage table */
23
  public:
24
  DEFINE_SIZE_ARRAY (6, values);
25
26
  bool sanitize (hb_sanitize_context_t *c) const
27
0
  {
28
0
    TRACE_SANITIZE (this);
29
0
    return_trace (c->check_struct (this) &&
30
0
                  coverage.sanitize (c, this) &&
31
0
      hb_barrier () &&
32
                  /* The coverage  table may use a range to represent a set
33
                   * of glyphs, which means a small number of bytes can
34
                   * generate a large glyph set. Manually modify the
35
                   * sanitizer max ops to take this into account.
36
                   *
37
                   * Note: This check *must* be right after coverage sanitize. */
38
0
                  c->check_ops ((this + coverage).get_population () >> 1) &&
39
0
                  valueFormat.sanitize_value (c, this, values));
40
41
0
  }
42
43
  bool intersects (const hb_set_t *glyphs) const
44
0
  { return (this+coverage).intersects (glyphs); }
45
46
0
  void closure_lookups (hb_closure_lookups_context_t *c) const {}
47
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
48
0
  {
49
0
    if (!valueFormat.has_device ()) return;
50
0
51
0
    hb_set_t intersection;
52
0
    (this+coverage).intersect_set (*c->glyph_set, intersection);
53
0
    if (!intersection) return;
54
0
55
0
    valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
56
0
  }
57
58
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
59
0
  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
60
61
0
  const Coverage &get_coverage () const { return this+coverage; }
62
63
0
  ValueFormat get_value_format () const { return valueFormat; }
64
65
  bool apply (hb_ot_apply_context_t *c) const
66
0
  {
67
0
    TRACE_APPLY (this);
68
0
    hb_buffer_t *buffer = c->buffer;
69
0
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
70
0
    if (index == NOT_COVERED) return_trace (false);
71
72
0
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
73
0
    {
74
0
      c->buffer->message (c->font,
75
0
        "positioning glyph at %u",
76
0
        c->buffer->idx);
77
0
    }
78
79
0
    valueFormat.apply_value (c, this, values, buffer->cur_pos());
80
81
0
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
82
0
    {
83
0
      c->buffer->message (c->font,
84
0
        "positioned glyph at %u",
85
0
        c->buffer->idx);
86
0
    }
87
88
0
    buffer->idx++;
89
0
    return_trace (true);
90
0
  }
91
92
  bool
93
  position_single (hb_font_t           *font,
94
       hb_blob_t           *table_blob,
95
       hb_direction_t       direction,
96
       hb_codepoint_t       gid,
97
       hb_glyph_position_t &pos) const
98
0
  {
99
0
    unsigned int index = (this+coverage).get_coverage  (gid);
100
0
    if (likely (index == NOT_COVERED)) return false;
101
102
    /* This is ugly... */
103
0
    hb_buffer_t buffer {};
104
0
    buffer.props.direction = direction;
105
0
    OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
106
107
0
    valueFormat.apply_value (&c, this, values, pos);
108
0
    return true;
109
0
  }
110
111
  template<typename Iterator,
112
      typename SrcLookup,
113
      hb_requires (hb_is_iterator (Iterator))>
114
  void serialize (hb_serialize_context_t *c,
115
                  const SrcLookup *src,
116
                  Iterator it,
117
                  ValueFormat newFormat,
118
                  const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map)
119
0
  {
120
0
    if (unlikely (!c->extend_min (this))) return;
121
0
    if (unlikely (!c->check_assign (valueFormat,
122
0
                                    newFormat,
123
0
                                    HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
124
0
125
0
    for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
126
0
    {
127
0
      src->get_value_format ().copy_values (c, newFormat, src,  &_, layout_variation_idx_delta_map);
128
0
      // Only serialize the first entry in the iterator, the rest are assumed to
129
0
      // be the same.
130
0
      break;
131
0
    }
132
0
133
0
    auto glyphs =
134
0
    + it
135
0
    | hb_map_retains_sorting (hb_first)
136
0
    ;
137
0
138
0
    coverage.serialize_serialize (c, glyphs);
139
0
  }
Unexecuted instantiation: _ZN2OT6Layout9GPOS_impl16SinglePosFormat19serializeI13hb_zip_iter_tI13hb_map_iter_tIN23hb_bit_set_invertible_t6iter_tERK8hb_map_tL24hb_function_sortedness_t1ELPv0EE16hb_repeat_iter_tI10hb_array_tIKNS_7NumTypeILb1EtLj2EEEEEES2_TnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSN_6item_tEEE5valueEvE4typeELSC_0EEEvP22hb_serialize_context_tPKT0_SN_NS1_11ValueFormatEPK12hb_hashmap_tIj9hb_pair_tIjiELb0EE
Unexecuted instantiation: hb-ot-face.cc:_ZN2OT6Layout9GPOS_impl16SinglePosFormat19serializeI13hb_map_iter_tI16hb_filter_iter_tI13hb_zip_iter_tINS0_6Common8Coverage6iter_tE15hb_range_iter_tIjjEERK8hb_set_tRK3$_6LPv0EEZNKS1_16SinglePosFormat26subsetEP19hb_subset_context_tEUlRK9hb_pair_tIjjEE_L24hb_function_sortedness_t1ELSJ_0EESL_TnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSW_6item_tEEE5valueEvE4typeELSJ_0EEEvP22hb_serialize_context_tPKT0_SW_NS1_11ValueFormatEPK12hb_hashmap_tIjSO_IjiELb0EE
Unexecuted instantiation: hb-aat-layout.cc:_ZN2OT6Layout9GPOS_impl16SinglePosFormat19serializeI13hb_map_iter_tI16hb_filter_iter_tI13hb_zip_iter_tINS0_6Common8Coverage6iter_tE15hb_range_iter_tIjjEERK8hb_set_tRK3$_6LPv0EEZNKS1_16SinglePosFormat26subsetEP19hb_subset_context_tEUlRK9hb_pair_tIjjEE_L24hb_function_sortedness_t1ELSJ_0EESL_TnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSW_6item_tEEE5valueEvE4typeELSJ_0EEEvP22hb_serialize_context_tPKT0_SW_NS1_11ValueFormatEPK12hb_hashmap_tIjSO_IjiELb0EE
Unexecuted instantiation: hb-ot-layout.cc:_ZN2OT6Layout9GPOS_impl16SinglePosFormat19serializeI13hb_map_iter_tI16hb_filter_iter_tI13hb_zip_iter_tINS0_6Common8Coverage6iter_tE15hb_range_iter_tIjjEERK8hb_set_tRK3$_6LPv0EEZNKS1_16SinglePosFormat26subsetEP19hb_subset_context_tEUlRK9hb_pair_tIjjEE_L24hb_function_sortedness_t1ELSJ_0EESL_TnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSW_6item_tEEE5valueEvE4typeELSJ_0EEEvP22hb_serialize_context_tPKT0_SW_NS1_11ValueFormatEPK12hb_hashmap_tIjSO_IjiELb0EE
Unexecuted instantiation: hb-ot-shape-fallback.cc:_ZN2OT6Layout9GPOS_impl16SinglePosFormat19serializeI13hb_map_iter_tI16hb_filter_iter_tI13hb_zip_iter_tINS0_6Common8Coverage6iter_tE15hb_range_iter_tIjjEERK8hb_set_tRK3$_6LPv0EEZNKS1_16SinglePosFormat26subsetEP19hb_subset_context_tEUlRK9hb_pair_tIjjEE_L24hb_function_sortedness_t1ELSJ_0EESL_TnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSW_6item_tEEE5valueEvE4typeELSJ_0EEEvP22hb_serialize_context_tPKT0_SW_NS1_11ValueFormatEPK12hb_hashmap_tIjSO_IjiELb0EE
140
141
  bool subset (hb_subset_context_t *c) const
142
0
  {
143
0
    TRACE_SUBSET (this);
144
0
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
145
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
146
0
147
0
    hb_set_t intersection;
148
0
    (this+coverage).intersect_set (glyphset, intersection);
149
0
150
0
    unsigned new_format = valueFormat;
151
0
152
0
    if (c->plan->normalized_coords)
153
0
    {
154
0
      new_format = valueFormat.get_effective_format (values.arrayZ, false, false, this, &c->plan->layout_variation_idx_delta_map);
155
0
    }
156
0
    /* do not strip hints for VF */
157
0
    else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
158
0
    {
159
0
      hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
160
0
      bool has_fvar = (blob != hb_blob_get_empty ());
161
0
      hb_blob_destroy (blob);
162
0
163
0
      bool strip = !has_fvar;
164
0
      /* special case: strip hints when a VF has no GDEF varstore after
165
0
       * subsetting*/
166
0
      if (has_fvar && !c->plan->has_gdef_varstore)
167
0
        strip = true;
168
0
      new_format = valueFormat.get_effective_format (values.arrayZ,
169
0
                                                     strip, /* strip hints */
170
0
                                                     true, /* strip empty */
171
0
                                                     this, nullptr);
172
0
    }
173
0
174
0
    auto it =
175
0
    + hb_iter (intersection)
176
0
    | hb_map_retains_sorting (glyph_map)
177
0
    | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
178
0
    ;
179
0
180
0
    bool ret = bool (it);
181
0
    SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format);
182
0
    return_trace (ret);
183
0
  }
184
};
185
186
}
187
}
188
}
189
190
#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH */