xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/Layout/GPOS/PairPosFormat1.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 #ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
2 #define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
3 
4 #include "PairSet.hh"
5 
6 namespace OT {
7 namespace Layout {
8 namespace GPOS_impl {
9 
10 
11 template <typename Types>
12 struct 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 
sanitizeOT::Layout::GPOS_impl::PairPosFormat1_334   bool sanitize (hb_sanitize_context_t *c) const
35   {
36     TRACE_SANITIZE (this);
37 
38     if (!c->check_struct (this)) return_trace (false);
39     hb_barrier ();
40 
41     unsigned int len1 = valueFormat[0].get_len ();
42     unsigned int len2 = valueFormat[1].get_len ();
43     typename PairSet::sanitize_closure_t closure =
44     {
45       valueFormat,
46       len1,
47       PairSet::get_size (len1, len2)
48     };
49 
50     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
51   }
52 
intersectsOT::Layout::GPOS_impl::PairPosFormat1_353   bool intersects (const hb_set_t *glyphs) const
54   {
55     auto &cov = this+coverage;
56 
57     if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
58     {
59       for (hb_codepoint_t g : glyphs->iter())
60       {
61 	unsigned i = cov.get_coverage (g);
62 	if ((this+pairSet[i]).intersects (glyphs, valueFormat))
63 	  return true;
64       }
65       return false;
66     }
67 
68     return
69     + hb_zip (cov, pairSet)
70     | hb_filter (*glyphs, hb_first)
71     | hb_map (hb_second)
72     | hb_map ([glyphs, this] (const typename Types::template OffsetTo<PairSet> &_)
73               { return (this+_).intersects (glyphs, valueFormat); })
74     | hb_any
75     ;
76   }
77 
closure_lookupsOT::Layout::GPOS_impl::PairPosFormat1_378   void closure_lookups (hb_closure_lookups_context_t *c) const {}
collect_variation_indicesOT::Layout::GPOS_impl::PairPosFormat1_379   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
80   {
81     if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;
82 
83     auto it =
84     + hb_zip (this+coverage, pairSet)
85     | hb_filter (c->glyph_set, hb_first)
86     | hb_map (hb_second)
87     ;
88 
89     if (!it) return;
90     + it
91     | hb_map (hb_add (this))
92     | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
93     ;
94   }
95 
collect_glyphsOT::Layout::GPOS_impl::PairPosFormat1_396   void collect_glyphs (hb_collect_glyphs_context_t *c) const
97   {
98     if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
99     unsigned int count = pairSet.len;
100     for (unsigned int i = 0; i < count; i++)
101       (this+pairSet[i]).collect_glyphs (c, valueFormat);
102   }
103 
get_coverageOT::Layout::GPOS_impl::PairPosFormat1_3104   const Coverage &get_coverage () const { return this+coverage; }
105 
applyOT::Layout::GPOS_impl::PairPosFormat1_3106   bool apply (hb_ot_apply_context_t *c) const
107   {
108     TRACE_APPLY (this);
109     hb_buffer_t *buffer = c->buffer;
110     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
111     if (likely (index == NOT_COVERED)) return_trace (false);
112 
113     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
114     skippy_iter.reset_fast (buffer->idx);
115     unsigned unsafe_to;
116     if (unlikely (!skippy_iter.next (&unsafe_to)))
117     {
118       buffer->unsafe_to_concat (buffer->idx, unsafe_to);
119       return_trace (false);
120     }
121 
122     return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
123   }
124 
subsetOT::Layout::GPOS_impl::PairPosFormat1_3125   bool subset (hb_subset_context_t *c) const
126   {
127     TRACE_SUBSET (this);
128 
129     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
130     const hb_map_t &glyph_map = *c->plan->glyph_map;
131 
132     auto *out = c->serializer->start_embed (*this);
133     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
134     out->format = format;
135 
136     hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat[0], valueFormat[1]);
137 
138     if (c->plan->normalized_coords)
139     {
140       /* all device flags will be dropped when full instancing, no need to strip
141        * hints, also do not strip emtpy cause we don't compute the new default
142        * value during stripping */
143       newFormats = compute_effective_value_formats (glyphset, false, false, &c->plan->layout_variation_idx_delta_map);
144     }
145     /* do not strip hints for VF */
146     else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
147     {
148       hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
149       bool has_fvar = (blob != hb_blob_get_empty ());
150       hb_blob_destroy (blob);
151 
152       bool strip = !has_fvar;
153       /* special case: strip hints when a VF has no GDEF varstore after
154        * subsetting*/
155       if (has_fvar && !c->plan->has_gdef_varstore)
156         strip = true;
157       newFormats = compute_effective_value_formats (glyphset, strip, true);
158     }
159 
160     out->valueFormat[0] = newFormats.first;
161     out->valueFormat[1] = newFormats.second;
162 
163     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
164 
165     + hb_zip (this+coverage, pairSet)
166     | hb_filter (glyphset, hb_first)
167     | hb_filter ([this, c, out] (const typename Types::template OffsetTo<PairSet>& _)
168                  {
169                    auto snap = c->serializer->snapshot ();
170                    auto *o = out->pairSet.serialize_append (c->serializer);
171                    if (unlikely (!o)) return false;
172                    bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
173                    if (!ret)
174                    {
175                      out->pairSet.pop ();
176                      c->serializer->revert (snap);
177                    }
178                    return ret;
179                  },
180                  hb_second)
181     | hb_map (hb_first)
182     | hb_map (glyph_map)
183     | hb_sink (new_coverage)
184     ;
185 
186     out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
187 
188     return_trace (bool (new_coverage));
189   }
190 
191 
compute_effective_value_formatsOT::Layout::GPOS_impl::PairPosFormat1_3192   hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset,
193                                                                  bool strip_hints, bool strip_empty,
194                                                                  const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
195   {
196     unsigned record_size = PairSet::get_size (valueFormat);
197 
198     unsigned format1 = 0;
199     unsigned format2 = 0;
200     for (const auto & _ :
201 	  + hb_zip (this+coverage, pairSet)
202 	  | hb_filter (glyphset, hb_first)
203 	  | hb_map (hb_second)
204 	)
205     {
206       const PairSet& set = (this + _);
207       const PairValueRecord *record = &set.firstPairValueRecord;
208 
209       unsigned count = set.len;
210       for (unsigned i = 0; i < count; i++)
211       {
212         if (record->intersects (glyphset))
213         {
214           format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 (), strip_hints, strip_empty, &set, varidx_delta_map);
215           format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]), strip_hints, strip_empty, &set, varidx_delta_map);
216         }
217         record = &StructAtOffset<const PairValueRecord> (record, record_size);
218       }
219 
220       if (format1 == valueFormat[0] && format2 == valueFormat[1])
221         break;
222     }
223 
224     return hb_pair (format1, format2);
225   }
226 };
227 
228 
229 }
230 }
231 }
232 
233 #endif  // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
234