1 /*
2  * Copyright © 2016  Google, Inc.
3  * Copyright © 2018  Ebrahim Byagowi
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  * Google Author(s): Sascha Brawer
26  */
27 
28 #ifndef HB_OT_COLOR_CPAL_TABLE_HH
29 #define HB_OT_COLOR_CPAL_TABLE_HH
30 
31 #include "hb-open-type.hh"
32 #include "hb-ot-color.h"
33 #include "hb-ot-name.h"
34 
35 
36 /*
37  * CPAL -- Color Palette
38  * https://docs.microsoft.com/en-us/typography/opentype/spec/cpal
39  */
40 #define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
41 
42 namespace OT {
43 
44 
45 struct CPALV1Tail
46 {
47   friend struct CPAL;
48 
49   private:
get_palette_flagsOT::CPALV1Tail50   hb_ot_color_palette_flags_t get_palette_flags (const void *base,
51 						 unsigned int palette_index,
52 						 unsigned int palette_count) const
53   {
54     if (!paletteFlagsZ) return HB_OT_COLOR_PALETTE_FLAG_DEFAULT;
55     return (hb_ot_color_palette_flags_t) (uint32_t)
56 	   (base+paletteFlagsZ).as_array (palette_count)[palette_index];
57   }
58 
get_palette_name_idOT::CPALV1Tail59   hb_ot_name_id_t get_palette_name_id (const void *base,
60 				       unsigned int palette_index,
61 				       unsigned int palette_count) const
62   {
63     if (!paletteLabelsZ) return HB_OT_NAME_ID_INVALID;
64     return (base+paletteLabelsZ).as_array (palette_count)[palette_index];
65   }
66 
get_color_name_idOT::CPALV1Tail67   hb_ot_name_id_t get_color_name_id (const void *base,
68 				     unsigned int color_index,
69 				     unsigned int color_count) const
70   {
71     if (!colorLabelsZ) return HB_OT_NAME_ID_INVALID;
72     return (base+colorLabelsZ).as_array (color_count)[color_index];
73   }
74 
75   public:
serializeOT::CPALV1Tail76   bool serialize (hb_serialize_context_t *c,
77                   unsigned palette_count,
78                   unsigned color_count,
79                   const void *base,
80                   const hb_map_t *color_index_map) const
81   {
82     TRACE_SERIALIZE (this);
83     auto *out = c->allocate_size<CPALV1Tail> (static_size);
84     if (unlikely (!out)) return_trace (false);
85 
86     out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
87     out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
88 
89     const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
90     if (colorLabelsZ)
91     {
92       c->push ();
93       for (const auto _ : colorLabels)
94       {
95         if (!color_index_map->has (_)) continue;
96         NameID new_color_idx;
97         new_color_idx = color_index_map->get (_);
98         if (!c->copy<NameID> (new_color_idx))
99         {
100           c->pop_discard ();
101           return_trace (false);
102         }
103       }
104       c->add_link (out->colorLabelsZ, c->pop_pack ());
105     }
106     return_trace (true);
107   }
108 
sanitizeOT::CPALV1Tail109   bool sanitize (hb_sanitize_context_t *c,
110 		 const void *base,
111 		 unsigned int palette_count,
112 		 unsigned int color_count) const
113   {
114     TRACE_SANITIZE (this);
115     return_trace (c->check_struct (this) &&
116 		  (!paletteFlagsZ  || (base+paletteFlagsZ).sanitize (c, palette_count)) &&
117 		  (!paletteLabelsZ || (base+paletteLabelsZ).sanitize (c, palette_count)) &&
118 		  (!colorLabelsZ   || (base+colorLabelsZ).sanitize (c, color_count)));
119   }
120 
121   protected:
122   NNOffset32To<UnsizedArrayOf<HBUINT32>>
123 		paletteFlagsZ;		/* Offset from the beginning of CPAL table to
124 					 * the Palette Type Array. Set to 0 if no array
125 					 * is provided. */
126   NNOffset32To<UnsizedArrayOf<NameID>>
127 		paletteLabelsZ;		/* Offset from the beginning of CPAL table to
128 					 * the palette labels array. Set to 0 if no
129 					 * array is provided. */
130   NNOffset32To<UnsizedArrayOf<NameID>>
131 		colorLabelsZ;		/* Offset from the beginning of CPAL table to
132 					 * the color labels array. Set to 0
133 					 * if no array is provided. */
134   public:
135   DEFINE_SIZE_STATIC (12);
136 };
137 
138 typedef HBUINT32 BGRAColor;
139 
140 struct CPAL
141 {
142   static constexpr hb_tag_t tableTag = HB_OT_TAG_CPAL;
143 
has_dataOT::CPAL144   bool has_data () const { return numPalettes; }
145 
get_sizeOT::CPAL146   unsigned int get_size () const
147   { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); }
148 
get_palette_countOT::CPAL149   unsigned int get_palette_count () const { return numPalettes; }
get_color_countOT::CPAL150   unsigned int   get_color_count () const { return numColors; }
151 
get_palette_flagsOT::CPAL152   hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette_index) const
153   { return v1 ().get_palette_flags (this, palette_index, numPalettes); }
154 
get_palette_name_idOT::CPAL155   hb_ot_name_id_t get_palette_name_id (unsigned int palette_index) const
156   { return v1 ().get_palette_name_id (this, palette_index, numPalettes); }
157 
get_color_name_idOT::CPAL158   hb_ot_name_id_t get_color_name_id (unsigned int color_index) const
159   { return v1 ().get_color_name_id (this, color_index, numColors); }
160 
get_palette_colorsOT::CPAL161   unsigned int get_palette_colors (unsigned int  palette_index,
162 				   unsigned int  start_offset,
163 				   unsigned int *color_count, /* IN/OUT.  May be NULL. */
164 				   hb_color_t   *colors       /* OUT.     May be NULL. */) const
165   {
166     if (unlikely (palette_index >= numPalettes))
167     {
168       if (color_count) *color_count = 0;
169       return 0;
170     }
171     unsigned int start_index = colorRecordIndicesZ[palette_index];
172     hb_array_t<const BGRAColor> all_colors ((this+colorRecordsZ).arrayZ, numColorRecords);
173     hb_array_t<const BGRAColor> palette_colors = all_colors.sub_array (start_index,
174 								       numColors);
175     if (color_count)
176     {
177       + palette_colors.sub_array (start_offset, color_count)
178       | hb_sink (hb_array (colors, *color_count))
179       ;
180     }
181     return numColors;
182   }
183 
184   private:
v1OT::CPAL185   const CPALV1Tail& v1 () const
186   {
187     if (version == 0) return Null (CPALV1Tail);
188     return StructAfter<CPALV1Tail> (*this);
189   }
190 
191   public:
serializeOT::CPAL192   bool serialize (hb_serialize_context_t *c,
193                   const hb_array_t<const BGRAColor> &color_records,
194                   const hb_array_t<const HBUINT16> &color_record_indices,
195                   const hb_map_t &color_record_index_map,
196                   const hb_set_t &retained_color_record_indices) const
197   {
198     TRACE_SERIALIZE (this);
199 
200     for (const auto idx : color_record_indices)
201     {
202       HBUINT16 new_idx;
203       if (idx == 0) new_idx = 0;
204       else new_idx = color_record_index_map.get (idx);
205       if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
206     }
207 
208     c->push ();
209     for (const auto _ : retained_color_record_indices.iter ())
210     {
211       if (!c->copy<BGRAColor> (color_records[_]))
212       {
213         c->pop_discard ();
214         return_trace (false);
215       }
216     }
217     c->add_link (colorRecordsZ, c->pop_pack ());
218     return_trace (true);
219   }
220 
subsetOT::CPAL221   bool subset (hb_subset_context_t *c) const
222   {
223     TRACE_SUBSET (this);
224     const hb_map_t *color_index_map = c->plan->colr_palettes;
225     if (color_index_map->is_empty ()) return_trace (false);
226 
227     hb_set_t retained_color_indices;
228     for (const auto _ : color_index_map->keys ())
229     {
230       if (_ == 0xFFFF) continue;
231       retained_color_indices.add (_);
232     }
233     if (retained_color_indices.is_empty ()) return_trace (false);
234 
235     auto *out = c->serializer->start_embed (*this);
236     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
237 
238     out->version = version;
239     out->numColors = retained_color_indices.get_population ();
240     out->numPalettes = numPalettes;
241 
242     const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
243     hb_map_t color_record_index_map;
244     hb_set_t retained_color_record_indices;
245 
246     unsigned record_count = 0;
247     for (const auto first_color_record_idx : colorRecordIndices)
248     {
249       for (unsigned retained_color_idx : retained_color_indices.iter ())
250       {
251         unsigned color_record_idx = first_color_record_idx + retained_color_idx;
252         if (color_record_index_map.has (color_record_idx)) continue;
253         color_record_index_map.set (color_record_idx, record_count);
254         retained_color_record_indices.add (color_record_idx);
255         record_count++;
256       }
257     }
258 
259     out->numColorRecords = record_count;
260     const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords);
261     if (!out->serialize (c->serializer, color_records, colorRecordIndices, color_record_index_map, retained_color_record_indices))
262       return_trace (false);
263 
264     if (version == 1)
265       return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
266 
267     return_trace (true);
268   }
269 
sanitizeOT::CPAL270   bool sanitize (hb_sanitize_context_t *c) const
271   {
272     TRACE_SANITIZE (this);
273     return_trace (c->check_struct (this) &&
274 		  (this+colorRecordsZ).sanitize (c, numColorRecords) &&
275 		  colorRecordIndicesZ.sanitize (c, numPalettes) &&
276 		  (version == 0 || v1 ().sanitize (c, this, numPalettes, numColors)));
277   }
278 
279   protected:
280   HBUINT16	version;		/* Table version number */
281   /* Version 0 */
282   HBUINT16	numColors;		/* Number of colors in each palette. */
283   HBUINT16	numPalettes;		/* Number of palettes in the table. */
284   HBUINT16	numColorRecords;	/* Total number of color records, combined for
285 					 * all palettes. */
286   NNOffset32To<UnsizedArrayOf<BGRAColor>>
287 		colorRecordsZ;		/* Offset from the beginning of CPAL table to
288 					 * the first ColorRecord. */
289   UnsizedArrayOf<HBUINT16>
290 		colorRecordIndicesZ;	/* Index of each palette’s first color record in
291 					 * the combined color record array. */
292 /*CPALV1Tail	v1;*/
293   public:
294   DEFINE_SIZE_ARRAY (12, colorRecordIndicesZ);
295 };
296 
297 } /* namespace OT */
298 
299 
300 #endif /* HB_OT_COLOR_CPAL_TABLE_HH */
301