#ifndef OT_LAYOUT_GPOS_GPOS_HH #define OT_LAYOUT_GPOS_GPOS_HH #include "../../../hb-ot-layout-common.hh" #include "../../../hb-ot-layout-gsubgpos.hh" #include "Common.hh" #include "PosLookup.hh" namespace OT { using Layout::GPOS_impl::PosLookup; namespace Layout { static void propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int len, unsigned int i, hb_direction_t direction, unsigned nesting_level = HB_MAX_NESTING_LEVEL); /* * GPOS -- Glyph Positioning * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos */ struct GPOS : GSUBGPOS { static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS; using Lookup = PosLookup; const PosLookup& get_lookup (unsigned int i) const { return static_cast (GSUBGPOS::get_lookup (i)); } static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer); static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer); bool subset (hb_subset_context_t *c) const { hb_subset_layout_context_t l (c, tableTag); return GSUBGPOS::subset (&l); } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (GSUBGPOS::sanitize (c)); } HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, hb_face_t *face) const; void collect_variation_indices (hb_collect_variation_indices_context_t *c) const { for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++) { if (!c->gpos_lookups->has (i)) continue; const PosLookup &l = get_lookup (i); l.dispatch (c); } } void closure_lookups (hb_face_t *face, const hb_set_t *glyphs, hb_set_t *lookup_indexes /* IN/OUT */) const { GSUBGPOS::closure_lookups (face, glyphs, lookup_indexes); } typedef GSUBGPOS::accelerator_t accelerator_t; }; static void propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int len, unsigned int i, hb_direction_t direction, unsigned nesting_level) { /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate * offset of glyph they are attached to. */ int chain = pos[i].attach_chain(), type = pos[i].attach_type(); if (likely (!chain)) return; pos[i].attach_chain() = 0; unsigned int j = (int) i + chain; if (unlikely (j >= len)) return; if (unlikely (!nesting_level)) return; propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1); assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE)); if (type & GPOS_impl::ATTACH_TYPE_CURSIVE) { if (HB_DIRECTION_IS_HORIZONTAL (direction)) pos[i].y_offset += pos[j].y_offset; else pos[i].x_offset += pos[j].x_offset; } else /*if (type & GPOS_impl::ATTACH_TYPE_MARK)*/ { pos[i].x_offset += pos[j].x_offset; pos[i].y_offset += pos[j].y_offset; assert (j < i); if (HB_DIRECTION_IS_FORWARD (direction)) for (unsigned int k = j; k < i; k++) { pos[i].x_offset -= pos[k].x_advance; pos[i].y_offset -= pos[k].y_advance; } else for (unsigned int k = j + 1; k < i + 1; k++) { pos[i].x_offset += pos[k].x_advance; pos[i].y_offset += pos[k].y_advance; } } } void GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { unsigned int count = buffer->len; for (unsigned int i = 0; i < count; i++) buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0; } void GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED) { //_hb_buffer_assert_gsubgpos_vars (buffer); } void GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) { _hb_buffer_assert_gsubgpos_vars (buffer); unsigned int len; hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len); hb_direction_t direction = buffer->props.direction; /* Handle attachments */ if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT) for (unsigned i = 0; i < len; i++) propagate_attachment_offsets (pos, len, i, direction); if (unlikely (font->slant)) { for (unsigned i = 0; i < len; i++) if (unlikely (pos[i].y_offset)) pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset); } } } struct GPOS_accelerator_t : Layout::GPOS::accelerator_t { GPOS_accelerator_t (hb_face_t *face) : Layout::GPOS::accelerator_t (face) {} }; } #endif /* OT_LAYOUT_GPOS_GPOS_HH */