| #ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH |
| #define OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH |
| |
| #include "Common.hh" |
| #include "ValueFormat.hh" |
| |
| namespace OT { |
| namespace Layout { |
| namespace GPOS_impl { |
| |
| struct SinglePosFormat1 |
| { |
| protected: |
| HBUINT16 format; /* Format identifier--format = 1 */ |
| Offset16To<Coverage> |
| coverage; /* Offset to Coverage table--from |
| * beginning of subtable */ |
| ValueFormat valueFormat; /* Defines the types of data in the |
| * ValueRecord */ |
| ValueRecord values; /* Defines positioning |
| * value(s)--applied to all glyphs in |
| * the Coverage table */ |
| public: |
| DEFINE_SIZE_ARRAY (6, values); |
| |
| bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| return_trace (c->check_struct (this) && |
| coverage.sanitize (c, this) && |
| /* The coverage table may use a range to represent a set |
| * of glyphs, which means a small number of bytes can |
| * generate a large glyph set. Manually modify the |
| * sanitizer max ops to take this into account. |
| * |
| * Note: This check *must* be right after coverage sanitize. */ |
| c->check_ops ((this + coverage).get_population () >> 1) && |
| valueFormat.sanitize_value (c, this, values)); |
| |
| } |
| |
| bool intersects (const hb_set_t *glyphs) const |
| { return (this+coverage).intersects (glyphs); } |
| |
| void closure_lookups (hb_closure_lookups_context_t *c) const {} |
| void collect_variation_indices (hb_collect_variation_indices_context_t *c) const |
| { |
| if (!valueFormat.has_device ()) return; |
| |
| hb_set_t intersection; |
| (this+coverage).intersect_set (*c->glyph_set, intersection); |
| if (!intersection) return; |
| |
| valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ())); |
| } |
| |
| void collect_glyphs (hb_collect_glyphs_context_t *c) const |
| { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } |
| |
| const Coverage &get_coverage () const { return this+coverage; } |
| |
| ValueFormat get_value_format () const { return valueFormat; } |
| |
| bool apply (hb_ot_apply_context_t *c) const |
| { |
| TRACE_APPLY (this); |
| hb_buffer_t *buffer = c->buffer; |
| unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); |
| if (likely (index == NOT_COVERED)) return_trace (false); |
| |
| if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) |
| { |
| c->buffer->message (c->font, |
| "positioning glyph at %u", |
| c->buffer->idx); |
| } |
| |
| valueFormat.apply_value (c, this, values, buffer->cur_pos()); |
| |
| if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) |
| { |
| c->buffer->message (c->font, |
| "positioned glyph at %u", |
| c->buffer->idx); |
| } |
| |
| buffer->idx++; |
| return_trace (true); |
| } |
| |
| bool |
| position_single (hb_font_t *font, |
| hb_blob_t *table_blob, |
| hb_direction_t direction, |
| hb_codepoint_t gid, |
| hb_glyph_position_t &pos) const |
| { |
| unsigned int index = (this+coverage).get_coverage (gid); |
| if (likely (index == NOT_COVERED)) return false; |
| |
| /* This is ugly... */ |
| hb_buffer_t buffer; |
| buffer.props.direction = direction; |
| OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); |
| |
| valueFormat.apply_value (&c, this, values, pos); |
| return true; |
| } |
| |
| template<typename Iterator, |
| typename SrcLookup, |
| hb_requires (hb_is_iterator (Iterator))> |
| void serialize (hb_serialize_context_t *c, |
| const SrcLookup *src, |
| Iterator it, |
| ValueFormat newFormat, |
| const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) |
| { |
| if (unlikely (!c->extend_min (this))) return; |
| if (unlikely (!c->check_assign (valueFormat, |
| newFormat, |
| HB_SERIALIZE_ERROR_INT_OVERFLOW))) return; |
| |
| for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second)) |
| { |
| src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); |
| // Only serialize the first entry in the iterator, the rest are assumed to |
| // be the same. |
| break; |
| } |
| |
| auto glyphs = |
| + it |
| | hb_map_retains_sorting (hb_first) |
| ; |
| |
| coverage.serialize_serialize (c, glyphs); |
| } |
| |
| bool subset (hb_subset_context_t *c) const |
| { |
| TRACE_SUBSET (this); |
| const hb_set_t &glyphset = *c->plan->glyphset_gsub (); |
| const hb_map_t &glyph_map = *c->plan->glyph_map; |
| |
| hb_set_t intersection; |
| (this+coverage).intersect_set (glyphset, intersection); |
| |
| auto it = |
| + hb_iter (intersection) |
| | hb_map_retains_sorting (glyph_map) |
| | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ()))) |
| ; |
| |
| bool ret = bool (it); |
| SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); |
| return_trace (ret); |
| } |
| }; |
| |
| } |
| } |
| } |
| |
| #endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH */ |