xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/Layout/GPOS/PairSet.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 #ifndef OT_LAYOUT_GPOS_PAIRSET_HH
2 #define OT_LAYOUT_GPOS_PAIRSET_HH
3 
4 #include "PairValueRecord.hh"
5 
6 namespace OT {
7 namespace Layout {
8 namespace GPOS_impl {
9 
10 
11 template <typename Types>
12 struct PairSet : ValueBase
13 {
14   template <typename Types2>
15   friend struct PairPosFormat1_3;
16 
17   using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
18 
19   protected:
20   HBUINT16              len;    /* Number of PairValueRecords */
21   PairValueRecord       firstPairValueRecord;
22                                 /* Array of PairValueRecords--ordered
23                                  * by GlyphID of the second glyph */
24   public:
25   DEFINE_SIZE_MIN (2);
26 
get_sizeOT::Layout::GPOS_impl::PairSet27   static unsigned get_size (unsigned len1, unsigned len2)
28   {
29     return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2);
30   }
get_sizeOT::Layout::GPOS_impl::PairSet31   static unsigned get_size (const ValueFormat valueFormats[2])
32   {
33     unsigned len1 = valueFormats[0].get_len ();
34     unsigned len2 = valueFormats[1].get_len ();
35     return get_size (len1, len2);
36   }
37 
38   struct sanitize_closure_t
39   {
40     const ValueFormat *valueFormats;
41     unsigned int len1; /* valueFormats[0].get_len() */
42     unsigned int stride; /* bytes */
43   };
44 
sanitizeOT::Layout::GPOS_impl::PairSet45   bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
46   {
47     TRACE_SANITIZE (this);
48     if (!(c->check_struct (this) &&
49 	  hb_barrier () &&
50           c->check_range (&firstPairValueRecord,
51                           len,
52                           closure->stride))) return_trace (false);
53     hb_barrier ();
54 
55     unsigned int count = len;
56     const PairValueRecord *record = &firstPairValueRecord;
57     return_trace (c->lazy_some_gpos ||
58 		  (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
59                    closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)));
60   }
61 
intersectsOT::Layout::GPOS_impl::PairSet62   bool intersects (const hb_set_t *glyphs,
63                    const ValueFormat *valueFormats) const
64   {
65     unsigned record_size = get_size (valueFormats);
66 
67     const PairValueRecord *record = &firstPairValueRecord;
68     unsigned int count = len;
69     for (unsigned int i = 0; i < count; i++)
70     {
71       if (glyphs->has (record->secondGlyph))
72         return true;
73       record = &StructAtOffset<const PairValueRecord> (record, record_size);
74     }
75     return false;
76   }
77 
collect_glyphsOT::Layout::GPOS_impl::PairSet78   void collect_glyphs (hb_collect_glyphs_context_t *c,
79                        const ValueFormat *valueFormats) const
80   {
81     unsigned record_size = get_size (valueFormats);
82 
83     const PairValueRecord *record = &firstPairValueRecord;
84     c->input->add_array (&record->secondGlyph, len, record_size);
85   }
86 
collect_variation_indicesOT::Layout::GPOS_impl::PairSet87   void collect_variation_indices (hb_collect_variation_indices_context_t *c,
88                                   const ValueFormat *valueFormats) const
89   {
90     unsigned record_size = get_size (valueFormats);
91 
92     const PairValueRecord *record = &firstPairValueRecord;
93     unsigned count = len;
94     for (unsigned i = 0; i < count; i++)
95     {
96       if (c->glyph_set->has (record->secondGlyph))
97       { record->collect_variation_indices (c, valueFormats, this); }
98 
99       record = &StructAtOffset<const PairValueRecord> (record, record_size);
100     }
101   }
102 
applyOT::Layout::GPOS_impl::PairSet103   bool apply (hb_ot_apply_context_t *c,
104               const ValueFormat *valueFormats,
105               unsigned int pos) const
106   {
107     TRACE_APPLY (this);
108     hb_buffer_t *buffer = c->buffer;
109     unsigned int len1 = valueFormats[0].get_len ();
110     unsigned int len2 = valueFormats[1].get_len ();
111     unsigned record_size = get_size (len1, len2);
112 
113     const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
114                                                 &firstPairValueRecord,
115                                                 len,
116                                                 record_size);
117     if (record)
118     {
119       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
120       {
121 	c->buffer->message (c->font,
122 			    "try kerning glyphs at %u,%u",
123 			    c->buffer->idx, pos);
124       }
125 
126       bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
127       bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
128 
129       if (applied_first || applied_second)
130 	if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
131 	{
132 	  c->buffer->message (c->font,
133 			      "kerned glyphs at %u,%u",
134 			      c->buffer->idx, pos);
135 	}
136 
137       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
138       {
139 	c->buffer->message (c->font,
140 			    "tried kerning glyphs at %u,%u",
141 			    c->buffer->idx, pos);
142       }
143 
144       if (applied_first || applied_second)
145         buffer->unsafe_to_break (buffer->idx, pos + 1);
146 
147       if (len2)
148       {
149 	pos++;
150       // https://github.com/harfbuzz/harfbuzz/issues/3824
151       // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
152       buffer->unsafe_to_break (buffer->idx, pos + 1);
153       }
154 
155       buffer->idx = pos;
156       return_trace (true);
157     }
158     buffer->unsafe_to_concat (buffer->idx, pos + 1);
159     return_trace (false);
160   }
161 
subsetOT::Layout::GPOS_impl::PairSet162   bool subset (hb_subset_context_t *c,
163                const ValueFormat valueFormats[2],
164                const ValueFormat newFormats[2]) const
165   {
166     TRACE_SUBSET (this);
167     auto snap = c->serializer->snapshot ();
168 
169     auto *out = c->serializer->start_embed (*this);
170     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
171     out->len = 0;
172 
173     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
174     const hb_map_t &glyph_map = *c->plan->glyph_map;
175 
176     unsigned len1 = valueFormats[0].get_len ();
177     unsigned len2 = valueFormats[1].get_len ();
178     unsigned record_size = get_size (len1, len2);
179 
180     typename PairValueRecord::context_t context =
181     {
182       this,
183       valueFormats,
184       newFormats,
185       len1,
186       &glyph_map,
187       &c->plan->layout_variation_idx_delta_map
188     };
189 
190     const PairValueRecord *record = &firstPairValueRecord;
191     unsigned count = len, num = 0;
192     for (unsigned i = 0; i < count; i++)
193     {
194       if (glyphset.has (record->secondGlyph)
195          && record->subset (c, &context)) num++;
196       record = &StructAtOffset<const PairValueRecord> (record, record_size);
197     }
198 
199     out->len = num;
200     if (!num) c->serializer->revert (snap);
201     return_trace (num);
202   }
203 };
204 
205 
206 }
207 }
208 }
209 
210 #endif  // OT_LAYOUT_GPOS_PAIRSET_HH
211