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
36namespace OT {
37namespace Layout {
38namespace Common {
39
40template<typename Iterator>
41static inline void Coverage_serialize (hb_serialize_context_t *c,
42 Iterator it);
43
44struct 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
60#ifndef HB_OPTIMIZE_SIZE
61 HB_ALWAYS_INLINE
62#endif
63 bool sanitize (hb_sanitize_context_t *c) const
64 {
65 TRACE_SANITIZE (this);
66 if (!u.format.sanitize (c)) return_trace (false);
67 switch (u.format)
68 {
69 case 1: return_trace (u.format1.sanitize (c));
70 case 2: return_trace (u.format2.sanitize (c));
71#ifndef HB_NO_BEYOND_64K
72 case 3: return_trace (u.format3.sanitize (c));
73 case 4: return_trace (u.format4.sanitize (c));
74#endif
75 default:return_trace (true);
76 }
77 }
78
79 /* Has interface. */
80 unsigned operator [] (hb_codepoint_t k) const { return get (k); }
81 bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; }
82 /* Predicate. */
83 bool operator () (hb_codepoint_t k) const { return has (k); }
84
85 unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
86 unsigned int get_coverage (hb_codepoint_t glyph_id) const
87 {
88 switch (u.format) {
89 case 1: return u.format1.get_coverage (glyph_id);
90 case 2: return u.format2.get_coverage (glyph_id);
91#ifndef HB_NO_BEYOND_64K
92 case 3: return u.format3.get_coverage (glyph_id);
93 case 4: return u.format4.get_coverage (glyph_id);
94#endif
95 default:return NOT_COVERED;
96 }
97 }
98
99 unsigned get_population () const
100 {
101 switch (u.format) {
102 case 1: return u.format1.get_population ();
103 case 2: return u.format2.get_population ();
104#ifndef HB_NO_BEYOND_64K
105 case 3: return u.format3.get_population ();
106 case 4: return u.format4.get_population ();
107#endif
108 default:return NOT_COVERED;
109 }
110 }
111
112 template <typename Iterator,
113 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
114 bool serialize (hb_serialize_context_t *c, Iterator glyphs)
115 {
116 TRACE_SERIALIZE (this);
117 if (unlikely (!c->extend_min (this))) return_trace (false);
118
119 unsigned count = hb_len (glyphs);
120 unsigned num_ranges = 0;
121 hb_codepoint_t last = (hb_codepoint_t) -2;
122 hb_codepoint_t max = 0;
123 bool unsorted = false;
124 for (auto g: glyphs)
125 {
126 if (last != (hb_codepoint_t) -2 && g < last)
127 unsorted = true;
128 if (last + 1 != g)
129 num_ranges++;
130 last = g;
131 if (g > max) max = g;
132 }
133 u.format = !unsorted && count <= num_ranges * 3 ? 1 : 2;
134
135#ifndef HB_NO_BEYOND_64K
136 if (max > 0xFFFFu)
137 u.format += 2;
138 if (unlikely (max > 0xFFFFFFu))
139#else
140 if (unlikely (max > 0xFFFFu))
141#endif
142 {
143 c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
144 return_trace (false);
145 }
146
147 switch (u.format)
148 {
149 case 1: return_trace (u.format1.serialize (c, glyphs));
150 case 2: return_trace (u.format2.serialize (c, glyphs));
151#ifndef HB_NO_BEYOND_64K
152 case 3: return_trace (u.format3.serialize (c, glyphs));
153 case 4: return_trace (u.format4.serialize (c, glyphs));
154#endif
155 default:return_trace (false);
156 }
157 }
158
159 bool subset (hb_subset_context_t *c) const
160 {
161 TRACE_SUBSET (this);
162 auto it =
163 + iter ()
164 | hb_take (c->plan->source->get_num_glyphs ())
165 | hb_map_retains_sorting (c->plan->glyph_map_gsub)
166 | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
167 ;
168
169 // Cache the iterator result as it will be iterated multiple times
170 // by the serialize code below.
171 hb_sorted_vector_t<hb_codepoint_t> glyphs (it);
172 Coverage_serialize (c->serializer, glyphs.iter ());
173 return_trace (bool (glyphs));
174 }
175
176 bool intersects (const hb_set_t *glyphs) const
177 {
178 switch (u.format)
179 {
180 case 1: return u.format1.intersects (glyphs);
181 case 2: return u.format2.intersects (glyphs);
182#ifndef HB_NO_BEYOND_64K
183 case 3: return u.format3.intersects (glyphs);
184 case 4: return u.format4.intersects (glyphs);
185#endif
186 default:return false;
187 }
188 }
189 bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
190 {
191 switch (u.format)
192 {
193 case 1: return u.format1.intersects_coverage (glyphs, index);
194 case 2: return u.format2.intersects_coverage (glyphs, index);
195#ifndef HB_NO_BEYOND_64K
196 case 3: return u.format3.intersects_coverage (glyphs, index);
197 case 4: return u.format4.intersects_coverage (glyphs, index);
198#endif
199 default:return false;
200 }
201 }
202
203 /* Might return false if array looks unsorted.
204 * Used for faster rejection of corrupt data. */
205 template <typename set_t>
206 bool collect_coverage (set_t *glyphs) const
207 {
208 switch (u.format)
209 {
210 case 1: return u.format1.collect_coverage (glyphs);
211 case 2: return u.format2.collect_coverage (glyphs);
212#ifndef HB_NO_BEYOND_64K
213 case 3: return u.format3.collect_coverage (glyphs);
214 case 4: return u.format4.collect_coverage (glyphs);
215#endif
216 default:return false;
217 }
218 }
219
220 template <typename IterableOut,
221 hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
222 void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
223 {
224 switch (u.format)
225 {
226 case 1: return u.format1.intersect_set (glyphs, intersect_glyphs);
227 case 2: return u.format2.intersect_set (glyphs, intersect_glyphs);
228#ifndef HB_NO_BEYOND_64K
229 case 3: return u.format3.intersect_set (glyphs, intersect_glyphs);
230 case 4: return u.format4.intersect_set (glyphs, intersect_glyphs);
231#endif
232 default:return ;
233 }
234 }
235
236 struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
237 {
238 static constexpr bool is_sorted_iterator = true;
239 iter_t (const Coverage &c_ = Null (Coverage))
240 {
241 hb_memset (this, 0, sizeof (*this));
242 format = c_.u.format;
243 switch (format)
244 {
245 case 1: u.format1.init (c_.u.format1); return;
246 case 2: u.format2.init (c_.u.format2); return;
247#ifndef HB_NO_BEYOND_64K
248 case 3: u.format3.init (c_.u.format3); return;
249 case 4: u.format4.init (c_.u.format4); return;
250#endif
251 default: return;
252 }
253 }
254 bool __more__ () const
255 {
256 switch (format)
257 {
258 case 1: return u.format1.__more__ ();
259 case 2: return u.format2.__more__ ();
260#ifndef HB_NO_BEYOND_64K
261 case 3: return u.format3.__more__ ();
262 case 4: return u.format4.__more__ ();
263#endif
264 default:return false;
265 }
266 }
267 void __next__ ()
268 {
269 switch (format)
270 {
271 case 1: u.format1.__next__ (); break;
272 case 2: u.format2.__next__ (); break;
273#ifndef HB_NO_BEYOND_64K
274 case 3: u.format3.__next__ (); break;
275 case 4: u.format4.__next__ (); break;
276#endif
277 default: break;
278 }
279 }
280 typedef hb_codepoint_t __item_t__;
281 __item_t__ __item__ () const { return get_glyph (); }
282
283 hb_codepoint_t get_glyph () const
284 {
285 switch (format)
286 {
287 case 1: return u.format1.get_glyph ();
288 case 2: return u.format2.get_glyph ();
289#ifndef HB_NO_BEYOND_64K
290 case 3: return u.format3.get_glyph ();
291 case 4: return u.format4.get_glyph ();
292#endif
293 default:return 0;
294 }
295 }
296 bool operator != (const iter_t& o) const
297 {
298 if (unlikely (format != o.format)) return true;
299 switch (format)
300 {
301 case 1: return u.format1 != o.u.format1;
302 case 2: return u.format2 != o.u.format2;
303#ifndef HB_NO_BEYOND_64K
304 case 3: return u.format3 != o.u.format3;
305 case 4: return u.format4 != o.u.format4;
306#endif
307 default:return false;
308 }
309 }
310 iter_t __end__ () const
311 {
312 iter_t it = {};
313 it.format = format;
314 switch (format)
315 {
316 case 1: it.u.format1 = u.format1.__end__ (); break;
317 case 2: it.u.format2 = u.format2.__end__ (); break;
318#ifndef HB_NO_BEYOND_64K
319 case 3: it.u.format3 = u.format3.__end__ (); break;
320 case 4: it.u.format4 = u.format4.__end__ (); break;
321#endif
322 default: break;
323 }
324 return it;
325 }
326
327 private:
328 unsigned int format;
329 union {
330#ifndef HB_NO_BEYOND_64K
331 CoverageFormat2_4<MediumTypes>::iter_t format4; /* Put this one first since it's larger; helps shut up compiler. */
332 CoverageFormat1_3<MediumTypes>::iter_t format3;
333#endif
334 CoverageFormat2_4<SmallTypes>::iter_t format2; /* Put this one first since it's larger; helps shut up compiler. */
335 CoverageFormat1_3<SmallTypes>::iter_t format1;
336 } u;
337 };
338 iter_t iter () const { return iter_t (*this); }
339};
340
341template<typename Iterator>
342static inline void
343Coverage_serialize (hb_serialize_context_t *c,
344 Iterator it)
345{ c->start_embed<Coverage> ()->serialize (c, it); }
346
347}
348}
349}
350
351#endif // #ifndef OT_LAYOUT_COMMON_COVERAGE_HH
352