comparison mupdf-source/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 #ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
2 #define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
3
4 #include "LigatureArray.hh"
5
6 namespace OT {
7 namespace Layout {
8 namespace GPOS_impl {
9
10
11 template <typename Types>
12 struct MarkLigPosFormat1_2
13 {
14 protected:
15 HBUINT16 format; /* Format identifier--format = 1 */
16 typename Types::template OffsetTo<Coverage>
17 markCoverage; /* Offset to Mark Coverage table--from
18 * beginning of MarkLigPos subtable */
19 typename Types::template OffsetTo<Coverage>
20 ligatureCoverage; /* Offset to Ligature Coverage
21 * table--from beginning of MarkLigPos
22 * subtable */
23 HBUINT16 classCount; /* Number of defined mark classes */
24 typename Types::template OffsetTo<MarkArray>
25 markArray; /* Offset to MarkArray table--from
26 * beginning of MarkLigPos subtable */
27 typename Types::template OffsetTo<LigatureArray>
28 ligatureArray; /* Offset to LigatureArray table--from
29 * beginning of MarkLigPos subtable */
30 public:
31 DEFINE_SIZE_STATIC (4 + 4 * Types::size);
32
33 bool sanitize (hb_sanitize_context_t *c) const
34 {
35 TRACE_SANITIZE (this);
36 return_trace (c->check_struct (this) &&
37 markCoverage.sanitize (c, this) &&
38 ligatureCoverage.sanitize (c, this) &&
39 markArray.sanitize (c, this) &&
40 ligatureArray.sanitize (c, this, (unsigned int) classCount));
41 }
42
43 bool intersects (const hb_set_t *glyphs) const
44 {
45 return (this+markCoverage).intersects (glyphs) &&
46 (this+ligatureCoverage).intersects (glyphs);
47 }
48
49 void closure_lookups (hb_closure_lookups_context_t *c) const {}
50
51 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
52 {
53 + hb_zip (this+markCoverage, this+markArray)
54 | hb_filter (c->glyph_set, hb_first)
55 | hb_map (hb_second)
56 | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
57 ;
58
59 hb_map_t klass_mapping;
60 Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
61
62 unsigned ligcount = (this+ligatureArray).len;
63 auto lig_iter =
64 + hb_zip (this+ligatureCoverage, hb_range (ligcount))
65 | hb_filter (c->glyph_set, hb_first)
66 | hb_map (hb_second)
67 ;
68
69 const LigatureArray& lig_array = this+ligatureArray;
70 for (const unsigned i : lig_iter)
71 {
72 hb_sorted_vector_t<unsigned> lig_indexes;
73 unsigned row_count = lig_array[i].rows;
74 for (unsigned row : + hb_range (row_count))
75 {
76 + hb_range ((unsigned) classCount)
77 | hb_filter (klass_mapping)
78 | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
79 | hb_sink (lig_indexes)
80 ;
81 }
82
83 lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
84 }
85 }
86
87 void collect_glyphs (hb_collect_glyphs_context_t *c) const
88 {
89 if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
90 if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
91 }
92
93 const Coverage &get_coverage () const { return this+markCoverage; }
94
95 bool apply (hb_ot_apply_context_t *c) const
96 {
97 TRACE_APPLY (this);
98 hb_buffer_t *buffer = c->buffer;
99 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
100 if (likely (mark_index == NOT_COVERED)) return_trace (false);
101
102 /* Now we search backwards for a non-mark glyph */
103 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
104 skippy_iter.reset (buffer->idx, 1);
105 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
106 unsigned unsafe_from;
107 if (!skippy_iter.prev (&unsafe_from))
108 {
109 buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
110 return_trace (false);
111 }
112
113 /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
114 //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
115
116 unsigned int j = skippy_iter.idx;
117 unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
118 if (lig_index == NOT_COVERED)
119 {
120 buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
121 return_trace (false);
122 }
123
124 const LigatureArray& lig_array = this+ligatureArray;
125 const LigatureAttach& lig_attach = lig_array[lig_index];
126
127 /* Find component to attach to */
128 unsigned int comp_count = lig_attach.rows;
129 if (unlikely (!comp_count))
130 {
131 buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
132 return_trace (false);
133 }
134
135 /* We must now check whether the ligature ID of the current mark glyph
136 * is identical to the ligature ID of the found ligature. If yes, we
137 * can directly use the component index. If not, we attach the mark
138 * glyph to the last component of the ligature. */
139 unsigned int comp_index;
140 unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
141 unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
142 unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
143 if (lig_id && lig_id == mark_id && mark_comp > 0)
144 comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
145 else
146 comp_index = comp_count - 1;
147
148 return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
149 }
150
151 bool subset (hb_subset_context_t *c) const
152 {
153 TRACE_SUBSET (this);
154 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
155 const hb_map_t &glyph_map = *c->plan->glyph_map;
156
157 auto *out = c->serializer->start_embed (*this);
158 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
159 out->format = format;
160
161 hb_map_t klass_mapping;
162 Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
163
164 if (!klass_mapping.get_population ()) return_trace (false);
165 out->classCount = klass_mapping.get_population ();
166
167 auto mark_iter =
168 + hb_zip (this+markCoverage, this+markArray)
169 | hb_filter (glyphset, hb_first)
170 ;
171
172 auto new_mark_coverage =
173 + mark_iter
174 | hb_map_retains_sorting (hb_first)
175 | hb_map_retains_sorting (glyph_map)
176 ;
177
178 if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
179 return_trace (false);
180
181 out->markArray.serialize_subset (c, markArray, this,
182 (this+markCoverage).iter (),
183 &klass_mapping);
184
185 auto new_ligature_coverage =
186 + hb_iter (this + ligatureCoverage)
187 | hb_filter (glyphset)
188 | hb_map_retains_sorting (glyph_map)
189 ;
190
191 if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
192 return_trace (false);
193
194 out->ligatureArray.serialize_subset (c, ligatureArray, this,
195 hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
196
197 return_trace (true);
198 }
199
200 };
201
202 }
203 }
204 }
205
206 #endif /* OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH */