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