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