#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT3_HH #define OT_LAYOUT_GPOS_ANCHORFORMAT3_HH namespace OT { namespace Layout { namespace GPOS_impl { struct AnchorFormat3 { protected: HBUINT16 format; /* Format identifier--format = 3 */ FWORD xCoordinate; /* Horizontal value--in design units */ FWORD yCoordinate; /* Vertical value--in design units */ Offset16To xDeviceTable; /* Offset to Device table for X * coordinate-- from beginning of * Anchor table (may be NULL) */ Offset16To yDeviceTable; /* Offset to Device table for Y * coordinate-- from beginning of * Anchor table (may be NULL) */ public: DEFINE_SIZE_STATIC (10); bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); return_trace (xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); } void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, float *x, float *y) const { hb_font_t *font = c->font; *x = font->em_fscale_x (xCoordinate); *y = font->em_fscale_y (yCoordinate); if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this)) { hb_barrier (); *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache); } if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this)) { hb_barrier (); *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); } } bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->embed (format))) return_trace (false); if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false); if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false); unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; if (x_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) { hb_pair_t *new_varidx_delta; if (!c->plan->layout_variation_idx_delta_map.has (x_varidx, &new_varidx_delta)) return_trace (false); x_varidx = hb_first (*new_varidx_delta); int delta = hb_second (*new_varidx_delta); if (delta != 0) { if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); } } unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; if (y_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) { hb_pair_t *new_varidx_delta; if (!c->plan->layout_variation_idx_delta_map.has (y_varidx, &new_varidx_delta)) return_trace (false); y_varidx = hb_first (*new_varidx_delta); int delta = hb_second (*new_varidx_delta); if (delta != 0) { if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); } } /* in case that all axes are pinned or no variations after instantiation, * both var_idxes will be mapped to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */ if (x_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX && y_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); if (!c->serializer->embed (xDeviceTable)) return_trace (false); if (!c->serializer->embed (yDeviceTable)) return_trace (false); out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map); out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map); return_trace (out); } void collect_variation_indices (hb_collect_variation_indices_context_t *c) const { (this+xDeviceTable).collect_variation_indices (c); (this+yDeviceTable).collect_variation_indices (c); } }; } } } #endif // OT_LAYOUT_GPOS_ANCHORFORMAT3_HH