1#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
2#define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
3
4#include "PairSet.hh"
5
6namespace OT {
7namespace Layout {
8namespace GPOS_impl {
9
10
11template <typename Types>
12struct PairPosFormat1_3
13{
14 using PairSet = GPOS_impl::PairSet<Types>;
15 using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
16
17 protected:
18 HBUINT16 format; /* Format identifier--format = 1 */
19 typename Types::template OffsetTo<Coverage>
20 coverage; /* Offset to Coverage table--from
21 * beginning of subtable */
22 ValueFormat valueFormat[2]; /* [0] Defines the types of data in
23 * ValueRecord1--for the first glyph
24 * in the pair--may be zero (0) */
25 /* [1] Defines the types of data in
26 * ValueRecord2--for the second glyph
27 * in the pair--may be zero (0) */
28 Array16Of<typename Types::template OffsetTo<PairSet>>
29 pairSet; /* Array of PairSet tables
30 * ordered by Coverage Index */
31 public:
32 DEFINE_SIZE_ARRAY (8 + Types::size, pairSet);
33
34 bool sanitize (hb_sanitize_context_t *c) const
35 {
36 TRACE_SANITIZE (this);
37
38 if (!c->check_struct (this)) return_trace (false);
39
40 unsigned int len1 = valueFormat[0].get_len ();
41 unsigned int len2 = valueFormat[1].get_len ();
42 typename PairSet::sanitize_closure_t closure =
43 {
44 valueFormat,
45 len1,
46 PairSet::get_size (len1, len2)
47 };
48
49 return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
50 }
51
52 bool intersects (const hb_set_t *glyphs) const
53 {
54 auto &cov = this+coverage;
55
56 if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
57 {
58 for (hb_codepoint_t g : glyphs->iter())
59 {
60 unsigned i = cov.get_coverage (g);
61 if ((this+pairSet[i]).intersects (glyphs, valueFormat))
62 return true;
63 }
64 return false;
65 }
66
67 return
68 + hb_zip (cov, pairSet)
69 | hb_filter (*glyphs, hb_first)
70 | hb_map (hb_second)
71 | hb_map ([glyphs, this] (const typename Types::template OffsetTo<PairSet> &_)
72 { return (this+_).intersects (glyphs, valueFormat); })
73 | hb_any
74 ;
75 }
76
77 void closure_lookups (hb_closure_lookups_context_t *c) const {}
78 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
79 {
80 if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;
81
82 auto it =
83 + hb_zip (this+coverage, pairSet)
84 | hb_filter (c->glyph_set, hb_first)
85 | hb_map (hb_second)
86 ;
87
88 if (!it) return;
89 + it
90 | hb_map (hb_add (this))
91 | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
92 ;
93 }
94
95 void collect_glyphs (hb_collect_glyphs_context_t *c) const
96 {
97 if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
98 unsigned int count = pairSet.len;
99 for (unsigned int i = 0; i < count; i++)
100 (this+pairSet[i]).collect_glyphs (c, valueFormat);
101 }
102
103 const Coverage &get_coverage () const { return this+coverage; }
104
105 bool apply (hb_ot_apply_context_t *c) const
106 {
107 TRACE_APPLY (this);
108 hb_buffer_t *buffer = c->buffer;
109 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
110 if (likely (index == NOT_COVERED)) return_trace (false);
111
112 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
113 skippy_iter.reset_fast (buffer->idx);
114 unsigned unsafe_to;
115 if (unlikely (!skippy_iter.next (&unsafe_to)))
116 {
117 buffer->unsafe_to_concat (buffer->idx, unsafe_to);
118 return_trace (false);
119 }
120
121 return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
122 }
123
124 bool subset (hb_subset_context_t *c) const
125 {
126 TRACE_SUBSET (this);
127
128 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
129 const hb_map_t &glyph_map = *c->plan->glyph_map;
130
131 auto *out = c->serializer->start_embed (*this);
132 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
133 out->format = format;
134 out->valueFormat[0] = valueFormat[0];
135 out->valueFormat[1] = valueFormat[1];
136 if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
137 {
138 hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
139 out->valueFormat[0] = newFormats.first;
140 out->valueFormat[1] = newFormats.second;
141 }
142
143 if (c->plan->all_axes_pinned)
144 {
145 out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags ();
146 out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags ();
147 }
148
149 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
150
151 + hb_zip (this+coverage, pairSet)
152 | hb_filter (glyphset, hb_first)
153 | hb_filter ([this, c, out] (const typename Types::template OffsetTo<PairSet>& _)
154 {
155 auto snap = c->serializer->snapshot ();
156 auto *o = out->pairSet.serialize_append (c->serializer);
157 if (unlikely (!o)) return false;
158 bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
159 if (!ret)
160 {
161 out->pairSet.pop ();
162 c->serializer->revert (snap);
163 }
164 return ret;
165 },
166 hb_second)
167 | hb_map (hb_first)
168 | hb_map (glyph_map)
169 | hb_sink (new_coverage)
170 ;
171
172 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
173
174 return_trace (bool (new_coverage));
175 }
176
177
178 hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
179 {
180 unsigned record_size = PairSet::get_size (valueFormat);
181
182 unsigned format1 = 0;
183 unsigned format2 = 0;
184 for (const auto & _ :
185 + hb_zip (this+coverage, pairSet)
186 | hb_filter (glyphset, hb_first)
187 | hb_map (hb_second)
188 )
189 {
190 const PairSet& set = (this + _);
191 const PairValueRecord *record = &set.firstPairValueRecord;
192
193 unsigned count = set.len;
194 for (unsigned i = 0; i < count; i++)
195 {
196 if (record->intersects (glyphset))
197 {
198 format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
199 format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
200 }
201 record = &StructAtOffset<const PairValueRecord> (record, record_size);
202 }
203
204 if (format1 == valueFormat[0] && format2 == valueFormat[1])
205 break;
206 }
207
208 return hb_pair (format1, format2);
209 }
210};
211
212
213}
214}
215}
216
217#endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
218