Imported Upstream version 8.2.2
[platform/upstream/harfbuzz.git] / src / OT / Layout / GPOS / MarkArray.hh
1 #ifndef OT_LAYOUT_GPOS_MARKARRAY_HH
2 #define OT_LAYOUT_GPOS_MARKARRAY_HH
3
4 #include "AnchorMatrix.hh"
5 #include "MarkRecord.hh"
6
7 namespace OT {
8 namespace Layout {
9 namespace GPOS_impl {
10
11 struct 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     bool ret = false;
86     unsigned new_length = 0;
87     for (const auto& mark_record : mark_iter) {
88       ret |= mark_record.subset (c, this, klass_mapping);
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 (ret);
97   }
98 };
99
100 HB_INTERNAL inline
101 void 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 */