1#ifndef OT_LAYOUT_GPOS_MARKARRAY_HH
2#define OT_LAYOUT_GPOS_MARKARRAY_HH
3
4#include "AnchorMatrix.hh"
5#include "MarkRecord.hh"
6
7namespace OT {
8namespace Layout {
9namespace GPOS_impl {
10
11struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Coverage order */
12{
13 bool sanitize (hb_sanitize_context_t *c) const
14 {
15 TRACE_SANITIZE (this);
16 return_trace (Array16Of<MarkRecord>::sanitize (c, this));
17 }
18
19 bool apply (hb_ot_apply_context_t *c,
20 unsigned int mark_index, unsigned int glyph_index,
21 const AnchorMatrix &anchors, unsigned int class_count,
22 unsigned int glyph_pos) const
23 {
24 TRACE_APPLY (this);
25 hb_buffer_t *buffer = c->buffer;
26 const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
27 unsigned int mark_class = record.klass;
28
29 const Anchor& mark_anchor = this + record.markAnchor;
30 bool found;
31 const Anchor& glyph_anchor = anchors.get_anchor (c, glyph_index, mark_class, class_count, &found);
32 /* If this subtable doesn't have an anchor for this base and this class,
33 * return false such that the subsequent subtables have a chance at it. */
34 if (unlikely (!found)) return_trace (false);
35
36 float mark_x, mark_y, base_x, base_y;
37
38 buffer->unsafe_to_break (glyph_pos, buffer->idx + 1);
39 mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
40 glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
41
42 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
43 {
44 c->buffer->message (c->font,
45 "attaching mark glyph at %u to glyph at %u",
46 c->buffer->idx, glyph_pos);
47 }
48
49 hb_glyph_position_t &o = buffer->cur_pos();
50 o.x_offset = roundf (base_x - mark_x);
51 o.y_offset = roundf (base_y - mark_y);
52 o.attach_type() = ATTACH_TYPE_MARK;
53 o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
54 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
55
56 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
57 {
58 c->buffer->message (c->font,
59 "attached mark glyph at %u to glyph at %u",
60 c->buffer->idx, glyph_pos);
61 }
62
63 buffer->idx++;
64 return_trace (true);
65 }
66
67 template <typename Iterator,
68 hb_requires (hb_is_iterator (Iterator))>
69 bool subset (hb_subset_context_t *c,
70 Iterator coverage,
71 const hb_map_t *klass_mapping) const
72 {
73 TRACE_SUBSET (this);
74 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
75
76 auto* out = c->serializer->start_embed (this);
77 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
78
79 auto mark_iter =
80 + hb_zip (coverage, this->iter ())
81 | hb_filter (glyphset, hb_first)
82 | hb_map (hb_second)
83 ;
84
85 unsigned new_length = 0;
86 for (const auto& mark_record : mark_iter) {
87 if (unlikely (!mark_record.subset (c, this, klass_mapping)))
88 return_trace (false);
89 new_length++;
90 }
91
92 if (unlikely (!c->serializer->check_assign (out->len, new_length,
93 HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
94 return_trace (false);
95
96 return_trace (true);
97 }
98};
99
100HB_INTERNAL inline
101void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage,
102 const MarkArray &mark_array,
103 const hb_set_t &glyphset,
104 hb_map_t* klass_mapping /* INOUT */)
105{
106 hb_set_t orig_classes;
107
108 + hb_zip (mark_coverage, mark_array)
109 | hb_filter (glyphset, hb_first)
110 | hb_map (hb_second)
111 | hb_map (&MarkRecord::get_class)
112 | hb_sink (orig_classes)
113 ;
114
115 unsigned idx = 0;
116 for (auto klass : orig_classes.iter ())
117 {
118 if (klass_mapping->has (klass)) continue;
119 klass_mapping->set (klass, idx);
120 idx++;
121 }
122}
123
124}
125}
126}
127
128#endif /* OT_LAYOUT_GPOS_MARKARRAY_HH */
129