• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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