1 /*
2 * Copyright © 2007,2008,2009 Red Hat, Inc.
3 * Copyright © 2010,2012 Google, Inc.
4 *
5 * This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod, Garret Rieger
27 */
28
29 #ifndef OT_LAYOUT_COMMON_COVERAGE_HH
30 #define OT_LAYOUT_COMMON_COVERAGE_HH
31
32 #include "../types.hh"
33 #include "CoverageFormat1.hh"
34 #include "CoverageFormat2.hh"
35
36 namespace OT {
37 namespace Layout {
38 namespace Common {
39
40 template<typename Iterator>
41 static inline void Coverage_serialize (hb_serialize_context_t *c,
42 Iterator it);
43
44 struct Coverage
45 {
46
47 protected:
48 union {
49 HBUINT16 format; /* Format identifier */
50 CoverageFormat1_3<SmallTypes> format1;
51 CoverageFormat2_4<SmallTypes> format2;
52 #ifndef HB_NO_BEYOND_64K
53 CoverageFormat1_3<MediumTypes>format3;
54 CoverageFormat2_4<MediumTypes>format4;
55 #endif
56 } u;
57 public:
58 DEFINE_SIZE_UNION (2, format);
59
sanitizeOT::Layout::Common::Coverage60 bool sanitize (hb_sanitize_context_t *c) const
61 {
62 TRACE_SANITIZE (this);
63 if (!u.format.sanitize (c)) return_trace (false);
64 switch (u.format)
65 {
66 case 1: return_trace (u.format1.sanitize (c));
67 case 2: return_trace (u.format2.sanitize (c));
68 #ifndef HB_NO_BEYOND_64K
69 case 3: return_trace (u.format3.sanitize (c));
70 case 4: return_trace (u.format4.sanitize (c));
71 #endif
72 default:return_trace (true);
73 }
74 }
75
76 /* Has interface. */
operator []OT::Layout::Common::Coverage77 unsigned operator [] (hb_codepoint_t k) const { return get (k); }
hasOT::Layout::Common::Coverage78 bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; }
79 /* Predicate. */
operator ()OT::Layout::Common::Coverage80 bool operator () (hb_codepoint_t k) const { return has (k); }
81
getOT::Layout::Common::Coverage82 unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
get_coverageOT::Layout::Common::Coverage83 unsigned int get_coverage (hb_codepoint_t glyph_id) const
84 {
85 switch (u.format) {
86 case 1: return u.format1.get_coverage (glyph_id);
87 case 2: return u.format2.get_coverage (glyph_id);
88 #ifndef HB_NO_BEYOND_64K
89 case 3: return u.format3.get_coverage (glyph_id);
90 case 4: return u.format4.get_coverage (glyph_id);
91 #endif
92 default:return NOT_COVERED;
93 }
94 }
95
get_populationOT::Layout::Common::Coverage96 unsigned get_population () const
97 {
98 switch (u.format) {
99 case 1: return u.format1.get_population ();
100 case 2: return u.format2.get_population ();
101 #ifndef HB_NO_BEYOND_64K
102 case 3: return u.format3.get_population ();
103 case 4: return u.format4.get_population ();
104 #endif
105 default:return NOT_COVERED;
106 }
107 }
108
109 template <typename Iterator,
110 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
serializeOT::Layout::Common::Coverage111 bool serialize (hb_serialize_context_t *c, Iterator glyphs)
112 {
113 TRACE_SERIALIZE (this);
114 if (unlikely (!c->extend_min (this))) return_trace (false);
115
116 unsigned count = 0;
117 unsigned num_ranges = 0;
118 hb_codepoint_t last = (hb_codepoint_t) -2;
119 for (auto g: glyphs)
120 {
121 if (last + 1 != g)
122 num_ranges++;
123 last = g;
124 count++;
125 }
126 u.format = count <= num_ranges * 3 ? 1 : 2;
127
128 #ifndef HB_NO_BEYOND_64K
129 if (count && last > 0xFFFFu)
130 u.format += 2;
131 #endif
132
133 switch (u.format)
134 {
135 case 1: return_trace (u.format1.serialize (c, glyphs));
136 case 2: return_trace (u.format2.serialize (c, glyphs));
137 #ifndef HB_NO_BEYOND_64K
138 case 3: return_trace (u.format3.serialize (c, glyphs));
139 case 4: return_trace (u.format4.serialize (c, glyphs));
140 #endif
141 default:return_trace (false);
142 }
143 }
144
subsetOT::Layout::Common::Coverage145 bool subset (hb_subset_context_t *c) const
146 {
147 TRACE_SUBSET (this);
148 auto it =
149 + iter ()
150 | hb_filter (c->plan->glyph_map_gsub)
151 | hb_map_retains_sorting (c->plan->glyph_map_gsub)
152 ;
153
154 // Cache the iterator result as it will be iterated multiple times
155 // by the serialize code below.
156 hb_sorted_vector_t<hb_codepoint_t> glyphs (it);
157 Coverage_serialize (c->serializer, glyphs.iter ());
158 return_trace (bool (glyphs));
159 }
160
intersectsOT::Layout::Common::Coverage161 bool intersects (const hb_set_t *glyphs) const
162 {
163 switch (u.format)
164 {
165 case 1: return u.format1.intersects (glyphs);
166 case 2: return u.format2.intersects (glyphs);
167 #ifndef HB_NO_BEYOND_64K
168 case 3: return u.format3.intersects (glyphs);
169 case 4: return u.format4.intersects (glyphs);
170 #endif
171 default:return false;
172 }
173 }
intersects_coverageOT::Layout::Common::Coverage174 bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
175 {
176 switch (u.format)
177 {
178 case 1: return u.format1.intersects_coverage (glyphs, index);
179 case 2: return u.format2.intersects_coverage (glyphs, index);
180 #ifndef HB_NO_BEYOND_64K
181 case 3: return u.format3.intersects_coverage (glyphs, index);
182 case 4: return u.format4.intersects_coverage (glyphs, index);
183 #endif
184 default:return false;
185 }
186 }
187
188 /* Might return false if array looks unsorted.
189 * Used for faster rejection of corrupt data. */
190 template <typename set_t>
collect_coverageOT::Layout::Common::Coverage191 bool collect_coverage (set_t *glyphs) const
192 {
193 switch (u.format)
194 {
195 case 1: return u.format1.collect_coverage (glyphs);
196 case 2: return u.format2.collect_coverage (glyphs);
197 #ifndef HB_NO_BEYOND_64K
198 case 3: return u.format3.collect_coverage (glyphs);
199 case 4: return u.format4.collect_coverage (glyphs);
200 #endif
201 default:return false;
202 }
203 }
204
205 template <typename IterableOut,
206 hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
intersect_setOT::Layout::Common::Coverage207 void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
208 {
209 switch (u.format)
210 {
211 case 1: return u.format1.intersect_set (glyphs, intersect_glyphs);
212 case 2: return u.format2.intersect_set (glyphs, intersect_glyphs);
213 #ifndef HB_NO_BEYOND_64K
214 case 3: return u.format3.intersect_set (glyphs, intersect_glyphs);
215 case 4: return u.format4.intersect_set (glyphs, intersect_glyphs);
216 #endif
217 default:return ;
218 }
219 }
220
221 struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
222 {
223 static constexpr bool is_sorted_iterator = true;
iter_tOT::Layout::Common::Coverage::iter_t224 iter_t (const Coverage &c_ = Null (Coverage))
225 {
226 hb_memset (this, 0, sizeof (*this));
227 format = c_.u.format;
228 switch (format)
229 {
230 case 1: u.format1.init (c_.u.format1); return;
231 case 2: u.format2.init (c_.u.format2); return;
232 #ifndef HB_NO_BEYOND_64K
233 case 3: u.format3.init (c_.u.format3); return;
234 case 4: u.format4.init (c_.u.format4); return;
235 #endif
236 default: return;
237 }
238 }
__more__OT::Layout::Common::Coverage::iter_t239 bool __more__ () const
240 {
241 switch (format)
242 {
243 case 1: return u.format1.__more__ ();
244 case 2: return u.format2.__more__ ();
245 #ifndef HB_NO_BEYOND_64K
246 case 3: return u.format3.__more__ ();
247 case 4: return u.format4.__more__ ();
248 #endif
249 default:return false;
250 }
251 }
__next__OT::Layout::Common::Coverage::iter_t252 void __next__ ()
253 {
254 switch (format)
255 {
256 case 1: u.format1.__next__ (); break;
257 case 2: u.format2.__next__ (); break;
258 #ifndef HB_NO_BEYOND_64K
259 case 3: u.format3.__next__ (); break;
260 case 4: u.format4.__next__ (); break;
261 #endif
262 default: break;
263 }
264 }
265 typedef hb_codepoint_t __item_t__;
__item__OT::Layout::Common::Coverage::iter_t266 __item_t__ __item__ () const { return get_glyph (); }
267
get_glyphOT::Layout::Common::Coverage::iter_t268 hb_codepoint_t get_glyph () const
269 {
270 switch (format)
271 {
272 case 1: return u.format1.get_glyph ();
273 case 2: return u.format2.get_glyph ();
274 #ifndef HB_NO_BEYOND_64K
275 case 3: return u.format3.get_glyph ();
276 case 4: return u.format4.get_glyph ();
277 #endif
278 default:return 0;
279 }
280 }
operator !=OT::Layout::Common::Coverage::iter_t281 bool operator != (const iter_t& o) const
282 {
283 if (unlikely (format != o.format)) return true;
284 switch (format)
285 {
286 case 1: return u.format1 != o.u.format1;
287 case 2: return u.format2 != o.u.format2;
288 #ifndef HB_NO_BEYOND_64K
289 case 3: return u.format3 != o.u.format3;
290 case 4: return u.format4 != o.u.format4;
291 #endif
292 default:return false;
293 }
294 }
__end__OT::Layout::Common::Coverage::iter_t295 iter_t __end__ () const
296 {
297 iter_t it = {};
298 it.format = format;
299 switch (format)
300 {
301 case 1: it.u.format1 = u.format1.__end__ (); break;
302 case 2: it.u.format2 = u.format2.__end__ (); break;
303 #ifndef HB_NO_BEYOND_64K
304 case 3: it.u.format3 = u.format3.__end__ (); break;
305 case 4: it.u.format4 = u.format4.__end__ (); break;
306 #endif
307 default: break;
308 }
309 return it;
310 }
311
312 private:
313 unsigned int format;
314 union {
315 #ifndef HB_NO_BEYOND_64K
316 CoverageFormat2_4<MediumTypes>::iter_t format4; /* Put this one first since it's larger; helps shut up compiler. */
317 CoverageFormat1_3<MediumTypes>::iter_t format3;
318 #endif
319 CoverageFormat2_4<SmallTypes>::iter_t format2; /* Put this one first since it's larger; helps shut up compiler. */
320 CoverageFormat1_3<SmallTypes>::iter_t format1;
321 } u;
322 };
iterOT::Layout::Common::Coverage323 iter_t iter () const { return iter_t (*this); }
324 };
325
326 template<typename Iterator>
327 static inline void
Coverage_serialize(hb_serialize_context_t * c,Iterator it)328 Coverage_serialize (hb_serialize_context_t *c,
329 Iterator it)
330 { c->start_embed<Coverage> ()->serialize (c, it); }
331
332 }
333 }
334 }
335
336 #endif // #ifndef OT_LAYOUT_COMMON_COVERAGE_HH
337