Imported Upstream version 8.2.2
[platform/upstream/harfbuzz.git] / src / OT / Layout / GPOS / PairSet.hh
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
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
27   static unsigned get_size (unsigned len1, unsigned len2)
28   {
29     return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2);
30   }
31   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
45   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        && c->check_range (&firstPairValueRecord,
50                           len,
51                           closure->stride))) return_trace (false);
52
53     unsigned int count = len;
54     const PairValueRecord *record = &firstPairValueRecord;
55     return_trace (c->lazy_some_gpos ||
56                   (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
57                    closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)));
58   }
59
60   bool intersects (const hb_set_t *glyphs,
61                    const ValueFormat *valueFormats) const
62   {
63     unsigned record_size = get_size (valueFormats);
64
65     const PairValueRecord *record = &firstPairValueRecord;
66     unsigned int count = len;
67     for (unsigned int i = 0; i < count; i++)
68     {
69       if (glyphs->has (record->secondGlyph))
70         return true;
71       record = &StructAtOffset<const PairValueRecord> (record, record_size);
72     }
73     return false;
74   }
75
76   void collect_glyphs (hb_collect_glyphs_context_t *c,
77                        const ValueFormat *valueFormats) const
78   {
79     unsigned record_size = get_size (valueFormats);
80
81     const PairValueRecord *record = &firstPairValueRecord;
82     c->input->add_array (&record->secondGlyph, len, record_size);
83   }
84
85   void collect_variation_indices (hb_collect_variation_indices_context_t *c,
86                                   const ValueFormat *valueFormats) const
87   {
88     unsigned record_size = get_size (valueFormats);
89
90     const PairValueRecord *record = &firstPairValueRecord;
91     unsigned count = len;
92     for (unsigned i = 0; i < count; i++)
93     {
94       if (c->glyph_set->has (record->secondGlyph))
95       { record->collect_variation_indices (c, valueFormats, this); }
96
97       record = &StructAtOffset<const PairValueRecord> (record, record_size);
98     }
99   }
100
101   bool apply (hb_ot_apply_context_t *c,
102               const ValueFormat *valueFormats,
103               unsigned int pos) const
104   {
105     TRACE_APPLY (this);
106     hb_buffer_t *buffer = c->buffer;
107     unsigned int len1 = valueFormats[0].get_len ();
108     unsigned int len2 = valueFormats[1].get_len ();
109     unsigned record_size = get_size (len1, len2);
110
111     const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
112                                                 &firstPairValueRecord,
113                                                 len,
114                                                 record_size);
115     if (record)
116     {
117       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
118       {
119         c->buffer->message (c->font,
120                             "try kerning glyphs at %u,%u",
121                             c->buffer->idx, pos);
122       }
123
124       bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
125       bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
126
127       if (applied_first || applied_second)
128         if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
129         {
130           c->buffer->message (c->font,
131                               "kerned glyphs at %u,%u",
132                               c->buffer->idx, pos);
133         }
134
135       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
136       {
137         c->buffer->message (c->font,
138                             "tried kerning glyphs at %u,%u",
139                             c->buffer->idx, pos);
140       }
141
142       if (applied_first || applied_second)
143         buffer->unsafe_to_break (buffer->idx, pos + 1);
144
145       if (len2)
146       {
147         pos++;
148       // https://github.com/harfbuzz/harfbuzz/issues/3824
149       // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
150       buffer->unsafe_to_break (buffer->idx, pos + 1);
151       }
152
153       buffer->idx = pos;
154       return_trace (true);
155     }
156     buffer->unsafe_to_concat (buffer->idx, pos + 1);
157     return_trace (false);
158   }
159
160   bool subset (hb_subset_context_t *c,
161                const ValueFormat valueFormats[2],
162                const ValueFormat newFormats[2]) const
163   {
164     TRACE_SUBSET (this);
165     auto snap = c->serializer->snapshot ();
166
167     auto *out = c->serializer->start_embed (*this);
168     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
169     out->len = 0;
170
171     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
172     const hb_map_t &glyph_map = *c->plan->glyph_map;
173
174     unsigned len1 = valueFormats[0].get_len ();
175     unsigned len2 = valueFormats[1].get_len ();
176     unsigned record_size = get_size (len1, len2);
177
178     typename PairValueRecord::context_t context =
179     {
180       this,
181       valueFormats,
182       newFormats,
183       len1,
184       &glyph_map,
185       &c->plan->layout_variation_idx_delta_map
186     };
187
188     const PairValueRecord *record = &firstPairValueRecord;
189     unsigned count = len, num = 0;
190     for (unsigned i = 0; i < count; i++)
191     {
192       if (glyphset.has (record->secondGlyph)
193          && record->subset (c, &context)) num++;
194       record = &StructAtOffset<const PairValueRecord> (record, record_size);
195     }
196
197     out->len = num;
198     if (!num) c->serializer->revert (snap);
199     return_trace (num);
200   }
201 };
202
203
204 }
205 }
206 }
207
208 #endif  // OT_LAYOUT_GPOS_PAIRSET_HH