xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/Color/CPAL/CPAL.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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:
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:
collect_name_idsOT::CPALV1Tail76   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 
serializeOT::CPALV1Tail100   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 
sanitizeOT::CPALV1Tail136   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 
has_dataOT::CPAL173   bool has_data () const { return numPalettes; }
174 
get_sizeOT::CPAL175   unsigned int get_size () const
176   { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); }
177 
get_palette_countOT::CPAL178   unsigned int get_palette_count () const { return numPalettes; }
get_color_countOT::CPAL179   unsigned int   get_color_count () const { return numColors; }
180 
get_palette_flagsOT::CPAL181   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 
get_palette_name_idOT::CPAL184   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 
get_color_name_idOT::CPAL187   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 
get_palette_colorsOT::CPAL190   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 
collect_name_idsOT::CPAL213   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     {
218       hb_barrier ();
219       v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain);
220     }
221   }
222 
223   private:
v1OT::CPAL224   const CPALV1Tail& v1 () const
225   {
226     if (version == 0) return Null (CPALV1Tail);
227     hb_barrier ();
228     return StructAfter<CPALV1Tail> (*this);
229   }
230 
231   public:
serializeOT::CPAL232   bool serialize (hb_serialize_context_t *c,
233                   const hb_array_t<const HBUINT16> &color_record_indices,
234                   const hb_array_t<const BGRAColor> &color_records,
235                   const hb_vector_t<unsigned>& first_color_index_for_layer,
236                   const hb_map_t& first_color_to_layer_index,
237                   const hb_set_t &retained_color_indices) const
238   {
239     TRACE_SERIALIZE (this);
240 
241     // TODO(grieger): limit total final size.
242 
243     for (const auto idx : color_record_indices)
244     {
245       hb_codepoint_t layer_index = first_color_to_layer_index[idx];
246 
247       HBUINT16 new_idx;
248       new_idx = layer_index * retained_color_indices.get_population ();
249       if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
250     }
251 
252     c->push ();
253     for (unsigned first_color_index : first_color_index_for_layer)
254     {
255       for (hb_codepoint_t color_index : retained_color_indices)
256       {
257         if (!c->copy<BGRAColor> (color_records[first_color_index + color_index]))
258         {
259           c->pop_discard ();
260           return_trace (false);
261         }
262       }
263     }
264 
265     c->add_link (colorRecordsZ, c->pop_pack ());
266     return_trace (true);
267   }
268 
subsetOT::CPAL269   bool subset (hb_subset_context_t *c) const
270   {
271     TRACE_SUBSET (this);
272     if (!numPalettes) return_trace (false);
273 
274     const hb_map_t *color_index_map = &c->plan->colr_palettes;
275     if (color_index_map->is_empty ()) return_trace (false);
276 
277     hb_set_t retained_color_indices;
278     for (const auto _ : color_index_map->keys ())
279     {
280       if (_ == 0xFFFF) continue;
281       retained_color_indices.add (_);
282     }
283     if (retained_color_indices.is_empty ()) return_trace (false);
284 
285     auto *out = c->serializer->start_embed (*this);
286     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
287 
288 
289     out->version = version;
290     out->numColors = retained_color_indices.get_population ();
291     out->numPalettes = numPalettes;
292 
293     hb_vector_t<unsigned> first_color_index_for_layer;
294     hb_map_t first_color_to_layer_index;
295 
296     const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
297     for (const auto first_color_record_idx : colorRecordIndices)
298     {
299       if (first_color_to_layer_index.has (first_color_record_idx)) continue;
300 
301       first_color_index_for_layer.push (first_color_record_idx);
302       first_color_to_layer_index.set (first_color_record_idx,
303                                       first_color_index_for_layer.length - 1);
304     }
305 
306     out->numColorRecords = first_color_index_for_layer.length
307                            * retained_color_indices.get_population ();
308 
309     const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords);
310     if (!out->serialize (c->serializer,
311                          colorRecordIndices,
312                          color_records,
313                          first_color_index_for_layer,
314                          first_color_to_layer_index,
315                          retained_color_indices))
316       return_trace (false);
317 
318     if (version == 1)
319     {
320       hb_barrier ();
321       return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
322     }
323 
324     return_trace (true);
325   }
326 
sanitizeOT::CPAL327   bool sanitize (hb_sanitize_context_t *c) const
328   {
329     TRACE_SANITIZE (this);
330     return_trace (c->check_struct (this) &&
331 		  hb_barrier () &&
332 		  (this+colorRecordsZ).sanitize (c, numColorRecords) &&
333 		  colorRecordIndicesZ.sanitize (c, numPalettes) &&
334 		  (version == 0 || v1 ().sanitize (c, this, numPalettes, numColors)));
335   }
336 
337   protected:
338   HBUINT16	version;		/* Table version number */
339   /* Version 0 */
340   HBUINT16	numColors;		/* Number of colors in each palette. */
341   HBUINT16	numPalettes;		/* Number of palettes in the table. */
342   HBUINT16	numColorRecords;	/* Total number of color records, combined for
343 					 * all palettes. */
344   NNOffset32To<UnsizedArrayOf<BGRAColor>>
345 		colorRecordsZ;		/* Offset from the beginning of CPAL table to
346 					 * the first ColorRecord. */
347   UnsizedArrayOf<HBUINT16>
348 		colorRecordIndicesZ;	/* Index of each palette’s first color record in
349 					 * the combined color record array. */
350 /*CPALV1Tail	v1;*/
351   public:
352   DEFINE_SIZE_ARRAY (12, colorRecordIndicesZ);
353 };
354 
355 } /* namespace OT */
356 
357 
358 #endif /* OT_COLOR_CPAL_CPAL_HH */
359