• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH
2 #define OT_LAYOUT_GPOS_VALUEFORMAT_HH
3 
4 #include "../../../hb-ot-layout-gsubgpos.hh"
5 
6 namespace OT {
7 namespace Layout {
8 namespace GPOS_impl {
9 
10 typedef HBUINT16 Value;
11 
12 typedef UnsizedArrayOf<Value> ValueRecord;
13 
14 struct ValueFormat : HBUINT16
15 {
16   enum Flags {
17     xPlacement  = 0x0001u,      /* Includes horizontal adjustment for placement */
18     yPlacement  = 0x0002u,      /* Includes vertical adjustment for placement */
19     xAdvance    = 0x0004u,      /* Includes horizontal adjustment for advance */
20     yAdvance    = 0x0008u,      /* Includes vertical adjustment for advance */
21     xPlaDevice  = 0x0010u,      /* Includes horizontal Device table for placement */
22     yPlaDevice  = 0x0020u,      /* Includes vertical Device table for placement */
23     xAdvDevice  = 0x0040u,      /* Includes horizontal Device table for advance */
24     yAdvDevice  = 0x0080u,      /* Includes vertical Device table for advance */
25     ignored     = 0x0F00u,      /* Was used in TrueType Open for MM fonts */
26     reserved    = 0xF000u,      /* For future use */
27 
28     devices     = 0x00F0u       /* Mask for having any Device table */
29   };
30 
31 /* All fields are options.  Only those available advance the value pointer. */
32 #if 0
33   HBINT16               xPlacement;     /* Horizontal adjustment for
34                                          * placement--in design units */
35   HBINT16               yPlacement;     /* Vertical adjustment for
36                                          * placement--in design units */
37   HBINT16               xAdvance;       /* Horizontal adjustment for
38                                          * advance--in design units (only used
39                                          * for horizontal writing) */
40   HBINT16               yAdvance;       /* Vertical adjustment for advance--in
41                                          * design units (only used for vertical
42                                          * writing) */
43   Offset16To<Device>    xPlaDevice;     /* Offset to Device table for
44                                          * horizontal placement--measured from
45                                          * beginning of PosTable (may be NULL) */
46   Offset16To<Device>    yPlaDevice;     /* Offset to Device table for vertical
47                                          * placement--measured from beginning
48                                          * of PosTable (may be NULL) */
49   Offset16To<Device>    xAdvDevice;     /* Offset to Device table for
50                                          * horizontal advance--measured from
51                                          * beginning of PosTable (may be NULL) */
52   Offset16To<Device>    yAdvDevice;     /* Offset to Device table for vertical
53                                          * advance--measured from beginning of
54                                          * PosTable (may be NULL) */
55 #endif
56 
operator =OT::Layout::GPOS_impl::ValueFormat57   IntType& operator = (uint16_t i) { v = i; return *this; }
58 
get_lenOT::Layout::GPOS_impl::ValueFormat59   unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
get_sizeOT::Layout::GPOS_impl::ValueFormat60   unsigned int get_size () const { return get_len () * Value::static_size; }
61 
get_device_table_indicesOT::Layout::GPOS_impl::ValueFormat62   hb_vector_t<unsigned> get_device_table_indices () const {
63     unsigned i = 0;
64     hb_vector_t<unsigned> result;
65     unsigned format = *this;
66 
67     if (format & xPlacement) i++;
68     if (format & yPlacement) i++;
69     if (format & xAdvance)   i++;
70     if (format & yAdvance)   i++;
71 
72     if (format & xPlaDevice) result.push (i++);
73     if (format & yPlaDevice) result.push (i++);
74     if (format & xAdvDevice) result.push (i++);
75     if (format & yAdvDevice) result.push (i++);
76 
77     return result;
78   }
79 
apply_valueOT::Layout::GPOS_impl::ValueFormat80   bool apply_value (hb_ot_apply_context_t *c,
81                     const void            *base,
82                     const Value           *values,
83                     hb_glyph_position_t   &glyph_pos) const
84   {
85     bool ret = false;
86     unsigned int format = *this;
87     if (!format) return ret;
88 
89     hb_font_t *font = c->font;
90     bool horizontal =
91 #ifndef HB_NO_VERTICAL
92       HB_DIRECTION_IS_HORIZONTAL (c->direction)
93 #else
94       true
95 #endif
96       ;
97 
98     if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++, &ret));
99     if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++, &ret));
100     if (format & xAdvance) {
101       if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret));
102       values++;
103     }
104     /* y_advance values grow downward but font-space grows upward, hence negation */
105     if (format & yAdvance) {
106       if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret));
107       values++;
108     }
109 
110     if (!has_device ()) return ret;
111 
112     bool use_x_device = font->x_ppem || font->num_coords;
113     bool use_y_device = font->y_ppem || font->num_coords;
114 
115     if (!use_x_device && !use_y_device) return ret;
116 
117     const VariationStore &store = c->var_store;
118     auto *cache = c->var_store_cache;
119 
120     /* pixel -> fractional pixel */
121     if (format & xPlaDevice)
122     {
123       if (use_x_device) glyph_pos.x_offset  += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
124       values++;
125     }
126     if (format & yPlaDevice)
127     {
128       if (use_y_device) glyph_pos.y_offset  += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
129       values++;
130     }
131     if (format & xAdvDevice)
132     {
133       if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
134       values++;
135     }
136     if (format & yAdvDevice)
137     {
138       /* y_advance values grow downward but font-space grows upward, hence negation */
139       if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
140       values++;
141     }
142     return ret;
143   }
144 
get_effective_formatOT::Layout::GPOS_impl::ValueFormat145   unsigned int get_effective_format (const Value *values) const
146   {
147     unsigned int format = *this;
148     for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
149       if (format & flag) should_drop (*values++, (Flags) flag, &format);
150     }
151 
152     return format;
153   }
154 
155   template<typename Iterator,
156       hb_requires (hb_is_iterator (Iterator))>
get_effective_formatOT::Layout::GPOS_impl::ValueFormat157   unsigned int get_effective_format (Iterator it) const {
158     unsigned int new_format = 0;
159 
160     for (const hb_array_t<const Value>& values : it)
161       new_format = new_format | get_effective_format (&values);
162 
163     return new_format;
164   }
165 
copy_valuesOT::Layout::GPOS_impl::ValueFormat166   void copy_values (hb_serialize_context_t *c,
167                     unsigned int new_format,
168                     const void *base,
169                     const Value *values,
170                     const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
171   {
172     unsigned int format = *this;
173     if (!format) return;
174 
175     HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr;
176     if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++);
177     if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++);
178     if (format & xAdvance)   x_adv = copy_value (c, new_format, xAdvance, *values++);
179     if (format & yAdvance)   y_adv = copy_value (c, new_format, yAdvance, *values++);
180 
181     if (!has_device ())
182       return;
183 
184     if (format & xPlaDevice)
185     {
186       add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
187       copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice);
188     }
189 
190     if (format & yPlaDevice)
191     {
192       add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map);
193       copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice);
194     }
195 
196     if (format & xAdvDevice)
197     {
198       add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map);
199       copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice);
200     }
201 
202     if (format & yAdvDevice)
203     {
204       add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map);
205       copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice);
206     }
207   }
208 
copy_valueOT::Layout::GPOS_impl::ValueFormat209   HBINT16* copy_value (hb_serialize_context_t *c,
210                        unsigned int new_format,
211                        Flags flag,
212                        Value value) const
213   {
214     // Filter by new format.
215     if (!(new_format & flag)) return nullptr;
216     return reinterpret_cast<HBINT16 *> (c->copy (value));
217   }
218 
collect_variation_indicesOT::Layout::GPOS_impl::ValueFormat219   void collect_variation_indices (hb_collect_variation_indices_context_t *c,
220                                   const void *base,
221                                   const hb_array_t<const Value>& values) const
222   {
223     unsigned format = *this;
224     unsigned i = 0;
225     if (format & xPlacement) i++;
226     if (format & yPlacement) i++;
227     if (format & xAdvance) i++;
228     if (format & yAdvance) i++;
229     if (format & xPlaDevice)
230     {
231       (base + get_device (&(values[i]))).collect_variation_indices (c);
232       i++;
233     }
234 
235     if (format & ValueFormat::yPlaDevice)
236     {
237       (base + get_device (&(values[i]))).collect_variation_indices (c);
238       i++;
239     }
240 
241     if (format & ValueFormat::xAdvDevice)
242     {
243       (base + get_device (&(values[i]))).collect_variation_indices (c);
244       i++;
245     }
246 
247     if (format & ValueFormat::yAdvDevice)
248     {
249       (base + get_device (&(values[i]))).collect_variation_indices (c);
250       i++;
251     }
252   }
253 
drop_device_table_flagsOT::Layout::GPOS_impl::ValueFormat254   unsigned drop_device_table_flags () const
255   {
256     unsigned format = *this;
257     for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1)
258       format = format & ~flag;
259 
260     return format;
261   }
262 
263   private:
sanitize_value_devicesOT::Layout::GPOS_impl::ValueFormat264   bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
265   {
266     unsigned int format = *this;
267 
268     if (format & xPlacement) values++;
269     if (format & yPlacement) values++;
270     if (format & xAdvance)   values++;
271     if (format & yAdvance)   values++;
272 
273     if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
274     if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
275     if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
276     if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
277 
278     return true;
279   }
280 
get_deviceOT::Layout::GPOS_impl::ValueFormat281   static inline Offset16To<Device>& get_device (Value* value)
282   {
283     return *static_cast<Offset16To<Device> *> (value);
284   }
get_deviceOT::Layout::GPOS_impl::ValueFormat285   static inline const Offset16To<Device>& get_device (const Value* value)
286   {
287     return *static_cast<const Offset16To<Device> *> (value);
288   }
get_deviceOT::Layout::GPOS_impl::ValueFormat289   static inline const Device& get_device (const Value* value,
290 					  bool *worked,
291 					  const void *base,
292 					  hb_sanitize_context_t &c)
293   {
294     if (worked) *worked |= bool (*value);
295     auto &offset = *static_cast<const Offset16To<Device> *> (value);
296 
297     if (unlikely (!offset.sanitize (&c, base)))
298       return Null(Device);
299 
300     return base + offset;
301   }
302 
add_delta_to_valueOT::Layout::GPOS_impl::ValueFormat303   void add_delta_to_value (HBINT16 *value,
304                            const void *base,
305                            const Value *src_value,
306                            const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
307   {
308     if (!value) return;
309     unsigned varidx = (base + get_device (src_value)).get_variation_index ();
310     hb_pair_t<unsigned, int> *varidx_delta;
311     if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return;
312 
313     *value += hb_second (*varidx_delta);
314   }
315 
copy_deviceOT::Layout::GPOS_impl::ValueFormat316   bool copy_device (hb_serialize_context_t *c, const void *base,
317                     const Value *src_value,
318                     const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
319                     unsigned int new_format, Flags flag) const
320   {
321     // Filter by new format.
322     if (!(new_format & flag)) return true;
323 
324     Value       *dst_value = c->copy (*src_value);
325 
326     if (!dst_value) return false;
327     if (*dst_value == 0) return true;
328 
329     *dst_value = 0;
330     c->push ();
331     if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map))
332     {
333       c->add_link (*dst_value, c->pop_pack ());
334       return true;
335     }
336     else
337     {
338       c->pop_discard ();
339       return false;
340     }
341   }
342 
get_shortOT::Layout::GPOS_impl::ValueFormat343   static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
344   {
345     if (worked) *worked |= bool (*value);
346     return *reinterpret_cast<const HBINT16 *> (value);
347   }
348 
349   public:
350 
has_deviceOT::Layout::GPOS_impl::ValueFormat351   bool has_device () const
352   {
353     unsigned int format = *this;
354     return (format & devices) != 0;
355   }
356 
sanitize_valueOT::Layout::GPOS_impl::ValueFormat357   bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
358   {
359     TRACE_SANITIZE (this);
360 
361     if (unlikely (!c->check_range (values, get_size ()))) return_trace (false);
362 
363     if (c->lazy_some_gpos)
364       return_trace (true);
365 
366     return_trace (!has_device () || sanitize_value_devices (c, base, values));
367   }
368 
sanitize_valuesOT::Layout::GPOS_impl::ValueFormat369   bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
370   {
371     TRACE_SANITIZE (this);
372     unsigned size = get_size ();
373 
374     if (!c->check_range (values, count, size)) return_trace (false);
375 
376     if (c->lazy_some_gpos)
377       return_trace (true);
378 
379     return_trace (sanitize_values_stride_unsafe (c, base, values, count, size));
380   }
381 
382   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
sanitize_values_stride_unsafeOT::Layout::GPOS_impl::ValueFormat383   bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
384   {
385     TRACE_SANITIZE (this);
386 
387     if (!has_device ()) return_trace (true);
388 
389     for (unsigned int i = 0; i < count; i++) {
390       if (!sanitize_value_devices (c, base, values))
391         return_trace (false);
392       values = &StructAtOffset<const Value> (values, stride);
393     }
394 
395     return_trace (true);
396   }
397 
398  private:
399 
should_dropOT::Layout::GPOS_impl::ValueFormat400   void should_drop (Value value, Flags flag, unsigned int* format) const
401   {
402     if (value) return;
403     *format = *format & ~flag;
404   }
405 
406 };
407 
408 }
409 }
410 }
411 
412 #endif  // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH
413