• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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       1 + len1 + len2
47     };
48 
49     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
50   }
51 
intersectsOT::Layout::GPOS_impl::PairPosFormat1_352   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 = HB_SET_VALUE_INVALID; glyphs->next (&g);)
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 
closure_lookupsOT::Layout::GPOS_impl::PairPosFormat1_377   void closure_lookups (hb_closure_lookups_context_t *c) const {}
collect_variation_indicesOT::Layout::GPOS_impl::PairPosFormat1_378   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 
collect_glyphsOT::Layout::GPOS_impl::PairPosFormat1_395   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 
get_coverageOT::Layout::GPOS_impl::PairPosFormat1_3103   const Coverage &get_coverage () const { return this+coverage; }
104 
applyOT::Layout::GPOS_impl::PairPosFormat1_3105   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 (buffer->idx, 1);
114     unsigned unsafe_to;
115     if (!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 
subsetOT::Layout::GPOS_impl::PairPosFormat1_3124   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 
compute_effective_value_formatsOT::Layout::GPOS_impl::PairPosFormat1_3178   hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
179   {
180     unsigned len1 = valueFormat[0].get_len ();
181     unsigned len2 = valueFormat[1].get_len ();
182     unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
183 
184     unsigned format1 = 0;
185     unsigned format2 = 0;
186     for (const auto & _ :
187 	  + hb_zip (this+coverage, pairSet)
188 	  | hb_filter (glyphset, hb_first)
189 	  | hb_map (hb_second)
190 	)
191     {
192       const PairSet& set = (this + _);
193       const PairValueRecord *record = &set.firstPairValueRecord;
194 
195       unsigned count = set.len;
196       for (unsigned i = 0; i < count; i++)
197       {
198         if (record->intersects (glyphset))
199         {
200           format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
201           format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
202         }
203         record = &StructAtOffset<const PairValueRecord> (record, record_size);
204       }
205 
206       if (format1 == valueFormat[0] && format2 == valueFormat[1])
207         break;
208     }
209 
210     return hb_pair (format1, format2);
211   }
212 };
213 
214 
215 }
216 }
217 }
218 
219 #endif  // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
220