1 | #ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH |
2 | #define OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH |
3 | |
4 | #include "Common.hh" |
5 | |
6 | namespace OT { |
7 | namespace Layout { |
8 | namespace GPOS_impl { |
9 | |
10 | struct SinglePosFormat2 |
11 | { |
12 | protected: |
13 | HBUINT16 format; /* Format identifier--format = 2 */ |
14 | Offset16To<Coverage> |
15 | coverage; /* Offset to Coverage table--from |
16 | * beginning of subtable */ |
17 | ValueFormat valueFormat; /* Defines the types of data in the |
18 | * ValueRecord */ |
19 | HBUINT16 valueCount; /* Number of ValueRecords */ |
20 | ValueRecord values; /* Array of ValueRecords--positioning |
21 | * values applied to glyphs */ |
22 | public: |
23 | DEFINE_SIZE_ARRAY (8, values); |
24 | |
25 | bool sanitize (hb_sanitize_context_t *c) const |
26 | { |
27 | TRACE_SANITIZE (this); |
28 | return_trace (c->check_struct (this) && |
29 | coverage.sanitize (c, this) && |
30 | valueFormat.sanitize_values (c, this, values, valueCount)); |
31 | } |
32 | |
33 | bool intersects (const hb_set_t *glyphs) const |
34 | { return (this+coverage).intersects (glyphs); } |
35 | |
36 | void closure_lookups (hb_closure_lookups_context_t *c) const {} |
37 | void collect_variation_indices (hb_collect_variation_indices_context_t *c) const |
38 | { |
39 | if (!valueFormat.has_device ()) return; |
40 | |
41 | auto it = |
42 | + hb_zip (this+coverage, hb_range ((unsigned) valueCount)) |
43 | | hb_filter (c->glyph_set, hb_first) |
44 | ; |
45 | |
46 | if (!it) return; |
47 | |
48 | unsigned sub_length = valueFormat.get_len (); |
49 | const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length); |
50 | |
51 | for (unsigned i : + it |
52 | | hb_map (hb_second)) |
53 | valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length)); |
54 | |
55 | } |
56 | |
57 | void collect_glyphs (hb_collect_glyphs_context_t *c) const |
58 | { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } |
59 | |
60 | const Coverage &get_coverage () const { return this+coverage; } |
61 | |
62 | ValueFormat get_value_format () const { return valueFormat; } |
63 | |
64 | bool apply (hb_ot_apply_context_t *c) const |
65 | { |
66 | TRACE_APPLY (this); |
67 | hb_buffer_t *buffer = c->buffer; |
68 | unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); |
69 | if (likely (index == NOT_COVERED)) return_trace (false); |
70 | |
71 | if (unlikely (index >= valueCount)) return_trace (false); |
72 | |
73 | if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) |
74 | { |
75 | c->buffer->message (c->font, |
76 | "positioning glyph at %u" , |
77 | c->buffer->idx); |
78 | } |
79 | |
80 | valueFormat.apply_value (c, this, |
81 | &values[index * valueFormat.get_len ()], |
82 | buffer->cur_pos()); |
83 | |
84 | if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) |
85 | { |
86 | c->buffer->message (c->font, |
87 | "positioned glyph at %u" , |
88 | c->buffer->idx); |
89 | } |
90 | |
91 | buffer->idx++; |
92 | return_trace (true); |
93 | } |
94 | |
95 | bool |
96 | position_single (hb_font_t *font, |
97 | hb_blob_t *table_blob, |
98 | hb_direction_t direction, |
99 | hb_codepoint_t gid, |
100 | hb_glyph_position_t &pos) const |
101 | { |
102 | unsigned int index = (this+coverage).get_coverage (gid); |
103 | if (likely (index == NOT_COVERED)) return false; |
104 | if (unlikely (index >= valueCount)) return false; |
105 | |
106 | /* This is ugly... */ |
107 | hb_buffer_t buffer; |
108 | buffer.props.direction = direction; |
109 | OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); |
110 | |
111 | valueFormat.apply_value (&c, this, |
112 | &values[index * valueFormat.get_len ()], |
113 | pos); |
114 | return true; |
115 | } |
116 | |
117 | |
118 | template<typename Iterator, |
119 | typename SrcLookup, |
120 | hb_requires (hb_is_iterator (Iterator))> |
121 | void serialize (hb_serialize_context_t *c, |
122 | const SrcLookup *src, |
123 | Iterator it, |
124 | ValueFormat newFormat, |
125 | const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) |
126 | { |
127 | auto out = c->extend_min (this); |
128 | if (unlikely (!out)) return; |
129 | if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return; |
130 | if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return; |
131 | |
132 | + it |
133 | | hb_map (hb_second) |
134 | | hb_apply ([&] (hb_array_t<const Value> _) |
135 | { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); }) |
136 | ; |
137 | |
138 | auto glyphs = |
139 | + it |
140 | | hb_map_retains_sorting (hb_first) |
141 | ; |
142 | |
143 | coverage.serialize_serialize (c, glyphs); |
144 | } |
145 | |
146 | bool subset (hb_subset_context_t *c) const |
147 | { |
148 | TRACE_SUBSET (this); |
149 | const hb_set_t &glyphset = *c->plan->glyphset_gsub (); |
150 | const hb_map_t &glyph_map = *c->plan->glyph_map; |
151 | |
152 | unsigned sub_length = valueFormat.get_len (); |
153 | auto values_array = values.as_array (valueCount * sub_length); |
154 | |
155 | auto it = |
156 | + hb_zip (this+coverage, hb_range ((unsigned) valueCount)) |
157 | | hb_filter (glyphset, hb_first) |
158 | | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _) |
159 | { |
160 | return hb_pair (glyph_map[_.first], |
161 | values_array.sub_array (_.second * sub_length, |
162 | sub_length)); |
163 | }) |
164 | ; |
165 | |
166 | bool ret = bool (it); |
167 | SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); |
168 | return_trace (ret); |
169 | } |
170 | }; |
171 | |
172 | |
173 | } |
174 | } |
175 | } |
176 | |
177 | #endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH */ |
178 | |