Imported Upstream version 3.4.0
[platform/upstream/harfbuzz.git] / src / OT / Color / CPAL / CPAL.hh
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 OT_COLOR_CPAL_CPAL_HH
29 #define OT_COLOR_CPAL_CPAL_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:
50   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
59   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
67   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:
76   void collect_name_ids (const void *base,
77                          unsigned palette_count,
78                          unsigned color_count,
79                          const hb_map_t *color_index_map,
80                          hb_set_t *nameids_to_retain /* OUT */) const
81   {
82     if (paletteLabelsZ)
83     {
84       + (base+paletteLabelsZ).as_array (palette_count)
85       | hb_sink (nameids_to_retain)
86       ;
87     }
88
89     if (colorLabelsZ)
90     {
91       const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
92       for (unsigned i = 0; i < color_count; i++)
93       {
94         if (!color_index_map->has (i)) continue;
95         nameids_to_retain->add (colorLabels[i]);
96       }
97     }
98   }
99
100   bool serialize (hb_serialize_context_t *c,
101                   unsigned palette_count,
102                   unsigned color_count,
103                   const void *base,
104                   const hb_map_t *color_index_map) const
105   {
106     TRACE_SERIALIZE (this);
107     auto *out = c->allocate_size<CPALV1Tail> (static_size);
108     if (unlikely (!out)) return_trace (false);
109
110     out->paletteFlagsZ = 0;
111     if (paletteFlagsZ)
112       out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
113
114     out->paletteLabelsZ = 0;
115     if (paletteLabelsZ)
116       out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
117
118     const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
119     if (colorLabelsZ)
120     {
121       c->push ();
122       for (unsigned i = 0; i < color_count; i++)
123       {
124         if (!color_index_map->has (i)) continue;
125         if (!c->copy<NameID> (colorLabels[i]))
126         {
127           c->pop_discard ();
128           return_trace (false);
129         }
130       }
131       c->add_link (out->colorLabelsZ, c->pop_pack ());
132     }
133     return_trace (true);
134   }
135
136   bool sanitize (hb_sanitize_context_t *c,
137                  const void *base,
138                  unsigned int palette_count,
139                  unsigned int color_count) const
140   {
141     TRACE_SANITIZE (this);
142     return_trace (c->check_struct (this) &&
143                   (!paletteFlagsZ  || (base+paletteFlagsZ).sanitize (c, palette_count)) &&
144                   (!paletteLabelsZ || (base+paletteLabelsZ).sanitize (c, palette_count)) &&
145                   (!colorLabelsZ   || (base+colorLabelsZ).sanitize (c, color_count)));
146   }
147
148   protected:
149   // TODO(garretrieger): these offsets can hold nulls so we should not be using non-null offsets
150   //                     here. Currently they are needed since UnsizedArrayOf doesn't define null_size
151   NNOffset32To<UnsizedArrayOf<HBUINT32>>
152                 paletteFlagsZ;          /* Offset from the beginning of CPAL table to
153                                          * the Palette Type Array. Set to 0 if no array
154                                          * is provided. */
155   NNOffset32To<UnsizedArrayOf<NameID>>
156                 paletteLabelsZ;         /* Offset from the beginning of CPAL table to
157                                          * the palette labels array. Set to 0 if no
158                                          * array is provided. */
159   NNOffset32To<UnsizedArrayOf<NameID>>
160                 colorLabelsZ;           /* Offset from the beginning of CPAL table to
161                                          * the color labels array. Set to 0
162                                          * if no array is provided. */
163   public:
164   DEFINE_SIZE_STATIC (12);
165 };
166
167 typedef HBUINT32 BGRAColor;
168
169 struct CPAL
170 {
171   static constexpr hb_tag_t tableTag = HB_OT_TAG_CPAL;
172
173   bool has_data () const { return numPalettes; }
174
175   unsigned int get_size () const
176   { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); }
177
178   unsigned int get_palette_count () const { return numPalettes; }
179   unsigned int   get_color_count () const { return numColors; }
180
181   hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette_index) const
182   { return v1 ().get_palette_flags (this, palette_index, numPalettes); }
183
184   hb_ot_name_id_t get_palette_name_id (unsigned int palette_index) const
185   { return v1 ().get_palette_name_id (this, palette_index, numPalettes); }
186
187   hb_ot_name_id_t get_color_name_id (unsigned int color_index) const
188   { return v1 ().get_color_name_id (this, color_index, numColors); }
189
190   unsigned int get_palette_colors (unsigned int  palette_index,
191                                    unsigned int  start_offset,
192                                    unsigned int *color_count, /* IN/OUT.  May be NULL. */
193                                    hb_color_t   *colors       /* OUT.     May be NULL. */) const
194   {
195     if (unlikely (palette_index >= numPalettes))
196     {
197       if (color_count) *color_count = 0;
198       return 0;
199     }
200     unsigned int start_index = colorRecordIndicesZ[palette_index];
201     hb_array_t<const BGRAColor> all_colors ((this+colorRecordsZ).arrayZ, numColorRecords);
202     hb_array_t<const BGRAColor> palette_colors = all_colors.sub_array (start_index,
203                                                                        numColors);
204     if (color_count)
205     {
206       + palette_colors.sub_array (start_offset, color_count)
207       | hb_sink (hb_array (colors, *color_count))
208       ;
209     }
210     return numColors;
211   }
212
213   void collect_name_ids (const hb_map_t *color_index_map,
214                          hb_set_t *nameids_to_retain /* OUT */) const
215   {
216     if (version == 1)
217       v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain);
218   }
219
220   private:
221   const CPALV1Tail& v1 () const
222   {
223     if (version == 0) return Null (CPALV1Tail);
224     return StructAfter<CPALV1Tail> (*this);
225   }
226
227   public:
228   bool serialize (hb_serialize_context_t *c,
229                   const hb_array_t<const HBUINT16> &color_record_indices,
230                   const hb_array_t<const BGRAColor> &color_records,
231                   const hb_vector_t<unsigned>& first_color_index_for_layer,
232                   const hb_map_t& first_color_to_layer_index,
233                   const hb_set_t &retained_color_indices) const
234   {
235     TRACE_SERIALIZE (this);
236
237     // TODO(grieger): limit total final size.
238
239     for (const auto idx : color_record_indices)
240     {
241       hb_codepoint_t layer_index = first_color_to_layer_index[idx];
242
243       HBUINT16 new_idx;
244       new_idx = layer_index * retained_color_indices.get_population ();
245       if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
246     }
247
248     c->push ();
249     for (unsigned first_color_index : first_color_index_for_layer)
250     {
251       for (hb_codepoint_t color_index : retained_color_indices)
252       {
253         if (!c->copy<BGRAColor> (color_records[first_color_index + color_index]))
254         {
255           c->pop_discard ();
256           return_trace (false);
257         }
258       }
259     }
260
261     c->add_link (colorRecordsZ, c->pop_pack ());
262     return_trace (true);
263   }
264
265   bool subset (hb_subset_context_t *c) const
266   {
267     TRACE_SUBSET (this);
268     if (!numPalettes) return_trace (false);
269
270     const hb_map_t *color_index_map = &c->plan->colr_palettes;
271     if (color_index_map->is_empty ()) return_trace (false);
272
273     hb_set_t retained_color_indices;
274     for (const auto _ : color_index_map->keys ())
275     {
276       if (_ == 0xFFFF) continue;
277       retained_color_indices.add (_);
278     }
279     if (retained_color_indices.is_empty ()) return_trace (false);
280
281     auto *out = c->serializer->start_embed (*this);
282     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
283
284
285     out->version = version;
286     out->numColors = retained_color_indices.get_population ();
287     out->numPalettes = numPalettes;
288
289     hb_vector_t<unsigned> first_color_index_for_layer;
290     hb_map_t first_color_to_layer_index;
291
292     const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
293     for (const auto first_color_record_idx : colorRecordIndices)
294     {
295       if (first_color_to_layer_index.has (first_color_record_idx)) continue;
296
297       first_color_index_for_layer.push (first_color_record_idx);
298       first_color_to_layer_index.set (first_color_record_idx,
299                                       first_color_index_for_layer.length - 1);
300     }
301
302     out->numColorRecords = first_color_index_for_layer.length
303                            * retained_color_indices.get_population ();
304
305     const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords);
306     if (!out->serialize (c->serializer,
307                          colorRecordIndices,
308                          color_records,
309                          first_color_index_for_layer,
310                          first_color_to_layer_index,
311                          retained_color_indices))
312       return_trace (false);
313
314     if (version == 1)
315       return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
316
317     return_trace (true);
318   }
319
320   bool sanitize (hb_sanitize_context_t *c) const
321   {
322     TRACE_SANITIZE (this);
323     return_trace (c->check_struct (this) &&
324                   (this+colorRecordsZ).sanitize (c, numColorRecords) &&
325                   colorRecordIndicesZ.sanitize (c, numPalettes) &&
326                   (version == 0 || v1 ().sanitize (c, this, numPalettes, numColors)));
327   }
328
329   protected:
330   HBUINT16      version;                /* Table version number */
331   /* Version 0 */
332   HBUINT16      numColors;              /* Number of colors in each palette. */
333   HBUINT16      numPalettes;            /* Number of palettes in the table. */
334   HBUINT16      numColorRecords;        /* Total number of color records, combined for
335                                          * all palettes. */
336   NNOffset32To<UnsizedArrayOf<BGRAColor>>
337                 colorRecordsZ;          /* Offset from the beginning of CPAL table to
338                                          * the first ColorRecord. */
339   UnsizedArrayOf<HBUINT16>
340                 colorRecordIndicesZ;    /* Index of each palette’s first color record in
341                                          * the combined color record array. */
342 /*CPALV1Tail    v1;*/
343   public:
344   DEFINE_SIZE_ARRAY (12, colorRecordIndicesZ);
345 };
346
347 } /* namespace OT */
348
349
350 #endif /* OT_COLOR_CPAL_CPAL_HH */