• 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       if (use_x_device) glyph_pos.x_offset  += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
123       values++;
124     }
125     if (format & yPlaDevice) {
126       if (use_y_device) glyph_pos.y_offset  += (base + get_device (values, &ret)).get_y_delta (font, store, cache);
127       values++;
128     }
129     if (format & xAdvDevice) {
130       if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
131       values++;
132     }
133     if (format & yAdvDevice) {
134       /* y_advance values grow downward but font-space grows upward, hence negation */
135       if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache);
136       values++;
137     }
138     return ret;
139   }
140 
get_effective_formatOT::Layout::GPOS_impl::ValueFormat141   unsigned int get_effective_format (const Value *values) const
142   {
143     unsigned int format = *this;
144     for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
145       if (format & flag) should_drop (*values++, (Flags) flag, &format);
146     }
147 
148     return format;
149   }
150 
151   template<typename Iterator,
152       hb_requires (hb_is_iterator (Iterator))>
get_effective_formatOT::Layout::GPOS_impl::ValueFormat153   unsigned int get_effective_format (Iterator it) const {
154     unsigned int new_format = 0;
155 
156     for (const hb_array_t<const Value>& values : it)
157       new_format = new_format | get_effective_format (&values);
158 
159     return new_format;
160   }
161 
copy_valuesOT::Layout::GPOS_impl::ValueFormat162   void copy_values (hb_serialize_context_t *c,
163                     unsigned int new_format,
164                     const void *base,
165                     const Value *values,
166                     const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
167   {
168     unsigned int format = *this;
169     if (!format) return;
170 
171     HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr;
172     if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++);
173     if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++);
174     if (format & xAdvance)   x_adv = copy_value (c, new_format, xAdvance, *values++);
175     if (format & yAdvance)   y_adv = copy_value (c, new_format, yAdvance, *values++);
176 
177     if (format & xPlaDevice)
178     {
179       add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
180       copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice);
181     }
182 
183     if (format & yPlaDevice)
184     {
185       add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map);
186       copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice);
187     }
188 
189     if (format & xAdvDevice)
190     {
191       add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map);
192       copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice);
193     }
194 
195     if (format & yAdvDevice)
196     {
197       add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map);
198       copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice);
199     }
200   }
201 
copy_valueOT::Layout::GPOS_impl::ValueFormat202   HBINT16* copy_value (hb_serialize_context_t *c,
203                        unsigned int new_format,
204                        Flags flag,
205                        Value value) const
206   {
207     // Filter by new format.
208     if (!(new_format & flag)) return nullptr;
209     return reinterpret_cast<HBINT16 *> (c->copy (value));
210   }
211 
collect_variation_indicesOT::Layout::GPOS_impl::ValueFormat212   void collect_variation_indices (hb_collect_variation_indices_context_t *c,
213                                   const void *base,
214                                   const hb_array_t<const Value>& values) const
215   {
216     unsigned format = *this;
217     unsigned i = 0;
218     if (format & xPlacement) i++;
219     if (format & yPlacement) i++;
220     if (format & xAdvance) i++;
221     if (format & yAdvance) i++;
222     if (format & xPlaDevice)
223     {
224       (base + get_device (&(values[i]))).collect_variation_indices (c);
225       i++;
226     }
227 
228     if (format & ValueFormat::yPlaDevice)
229     {
230       (base + get_device (&(values[i]))).collect_variation_indices (c);
231       i++;
232     }
233 
234     if (format & ValueFormat::xAdvDevice)
235     {
236 
237       (base + get_device (&(values[i]))).collect_variation_indices (c);
238       i++;
239     }
240 
241     if (format & ValueFormat::yAdvDevice)
242     {
243 
244       (base + get_device (&(values[i]))).collect_variation_indices (c);
245       i++;
246     }
247   }
248 
drop_device_table_flagsOT::Layout::GPOS_impl::ValueFormat249   unsigned drop_device_table_flags () const
250   {
251     unsigned format = *this;
252     for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1)
253       format = format & ~flag;
254 
255     return format;
256   }
257 
258   private:
sanitize_value_devicesOT::Layout::GPOS_impl::ValueFormat259   bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
260   {
261     unsigned int format = *this;
262 
263     if (format & xPlacement) values++;
264     if (format & yPlacement) values++;
265     if (format & xAdvance)   values++;
266     if (format & yAdvance)   values++;
267 
268     if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
269     if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
270     if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
271     if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
272 
273     return true;
274   }
275 
get_deviceOT::Layout::GPOS_impl::ValueFormat276   static inline Offset16To<Device>& get_device (Value* value)
277   {
278     return *static_cast<Offset16To<Device> *> (value);
279   }
get_deviceOT::Layout::GPOS_impl::ValueFormat280   static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
281   {
282     if (worked) *worked |= bool (*value);
283     return *static_cast<const Offset16To<Device> *> (value);
284   }
285 
add_delta_to_valueOT::Layout::GPOS_impl::ValueFormat286   void add_delta_to_value (HBINT16 *value,
287                            const void *base,
288                            const Value *src_value,
289                            const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
290   {
291     if (!value) return;
292     unsigned varidx = (base + get_device (src_value)).get_variation_index ();
293     hb_pair_t<unsigned, int> *varidx_delta;
294     if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return;
295 
296     *value += hb_second (*varidx_delta);
297   }
298 
copy_deviceOT::Layout::GPOS_impl::ValueFormat299   bool copy_device (hb_serialize_context_t *c, const void *base,
300                     const Value *src_value,
301                     const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
302                     unsigned int new_format, Flags flag) const
303   {
304     // Filter by new format.
305     if (!(new_format & flag)) return true;
306 
307     Value       *dst_value = c->copy (*src_value);
308 
309     if (!dst_value) return false;
310     if (*dst_value == 0) return true;
311 
312     *dst_value = 0;
313     c->push ();
314     if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map))
315     {
316       c->add_link (*dst_value, c->pop_pack ());
317       return true;
318     }
319     else
320     {
321       c->pop_discard ();
322       return false;
323     }
324   }
325 
get_shortOT::Layout::GPOS_impl::ValueFormat326   static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
327   {
328     if (worked) *worked |= bool (*value);
329     return *reinterpret_cast<const HBINT16 *> (value);
330   }
331 
332   public:
333 
has_deviceOT::Layout::GPOS_impl::ValueFormat334   bool has_device () const
335   {
336     unsigned int format = *this;
337     return (format & devices) != 0;
338   }
339 
sanitize_valueOT::Layout::GPOS_impl::ValueFormat340   bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
341   {
342     TRACE_SANITIZE (this);
343     return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
344   }
345 
sanitize_valuesOT::Layout::GPOS_impl::ValueFormat346   bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
347   {
348     TRACE_SANITIZE (this);
349     unsigned int len = get_len ();
350 
351     if (!c->check_range (values, count, get_size ())) return_trace (false);
352 
353     if (!has_device ()) return_trace (true);
354 
355     for (unsigned int i = 0; i < count; i++) {
356       if (!sanitize_value_devices (c, base, values))
357         return_trace (false);
358       values += len;
359     }
360 
361     return_trace (true);
362   }
363 
364   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
sanitize_values_stride_unsafeOT::Layout::GPOS_impl::ValueFormat365   bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
366   {
367     TRACE_SANITIZE (this);
368 
369     if (!has_device ()) return_trace (true);
370 
371     for (unsigned int i = 0; i < count; i++) {
372       if (!sanitize_value_devices (c, base, values))
373         return_trace (false);
374       values += stride;
375     }
376 
377     return_trace (true);
378   }
379 
380  private:
381 
should_dropOT::Layout::GPOS_impl::ValueFormat382   void should_drop (Value value, Flags flag, unsigned int* format) const
383   {
384     if (value) return;
385     *format = *format & ~flag;
386   }
387 
388 };
389 
390 }
391 }
392 }
393 
394 #endif  // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH
395