blob: d3019f1fed3dc24d27f04c295da8d12b8afc1b0d [file]
#ifndef OT_LAYOUT_GPOS_LIGATUREARRAY_HH
#define OT_LAYOUT_GPOS_LIGATUREARRAY_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
HB_INTERNAL inline
void collect_ligature_variation_indices (hb_collect_variation_indices_context_t *c,
const Coverage &coverage,
const void *base,
glyph_data_t offsets,
unsigned count,
unsigned class_count,
const hb_map_t &klass_mapping)
{
for (const auto _ : hb_zip (coverage, hb_range (count)))
{
if (!c->glyph_set->has (_.first)) continue;
hb_barrier ();
unsigned offset = offsets[_.second];
if (!offset) continue;
const void *matrix = &StructAtOffset<const HBUINT16> (base, offset);
/* LigatureAttach always has a 16-bit component count; its anchor
* offsets have the same width as the LigatureArray offsets. */
unsigned rows = *static_cast<const HBUINT16 *> (matrix);
glyph_data_t anchors = offsets;
anchors.data = (const char *) matrix + HBUINT16::static_size;
hb_sorted_vector_t<unsigned> indexes;
collect_ligature_anchor_indexes (rows, class_count, klass_mapping, indexes);
collect_anchor_variation_indices (c, matrix, anchors, indexes.iter ());
}
}
/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
template <typename Types>
struct LigatureArray :
Types::template ArrayOf<typename Types::template OffsetTo<AnchorMatrix<Types, HBUINT16>>>
{
typedef AnchorMatrix<Types, HBUINT16> LigatureAttach;
typedef typename Types::template OffsetTo<LigatureAttach> LigatureAttachOffset;
typedef typename Types::template ArrayOf<LigatureAttachOffset> Super;
const LigatureAttach& operator [] (int i_) const
{
unsigned int i = (unsigned int) i_;
if (unlikely (i >= this->len)) return Null (LigatureAttach);
hb_barrier ();
return this+this->arrayZ[i];
}
template <typename ...Ts>
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
return_trace (Super::sanitize (c, this, std::forward<Ts> (ds)...));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const Coverage &coverage,
unsigned class_count,
const hb_map_t &klass_mapping) const
{
collect_ligature_variation_indices (c, coverage, this, this->arrayZ,
this->len, class_count, klass_mapping);
}
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool subset (hb_subset_context_t *c,
Iterator coverage,
unsigned class_count,
const hb_map_t *klass_mapping,
hb_sorted_vector_t<hb_codepoint_t> &new_coverage /* OUT */) const
{
TRACE_SUBSET (this);
const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
bool ret = false;
for (const auto _ : + hb_zip (coverage, *this)
| hb_filter (glyph_map, hb_first))
{
const LigatureAttach& src = (this + _.second);
bool non_empty = + hb_range (src.rows * class_count)
| hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
| hb_map ([&] (const unsigned index) { return !src.offset_is_null (index / class_count, index % class_count, class_count); })
| hb_any;
if (!non_empty) continue;
auto *matrix = out->serialize_append (c->serializer);
if (unlikely (!matrix)) return_trace (false);
auto indexes =
+ hb_range (src.rows * class_count)
| hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
;
ret |= matrix->serialize_subset (c,
_.second,
this,
src.rows,
indexes);
hb_codepoint_t new_gid = glyph_map.get (_.first);
new_coverage.push (new_gid);
}
return_trace (ret);
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_LIGATUREARRAY_HH */