2 * Copyright © 2016 Google, Inc.
3 * Copyright © 2018 Ebrahim Byagowi
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Google Author(s): Sascha Brawer
28 #ifndef OT_COLOR_CPAL_CPAL_HH
29 #define OT_COLOR_CPAL_CPAL_HH
31 #include "../../../hb-open-type.hh"
32 #include "../../../hb-ot-color.h"
33 #include "../../../hb-ot-name.h"
37 * CPAL -- Color Palette
38 * https://docs.microsoft.com/en-us/typography/opentype/spec/cpal
40 #define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
50 hb_ot_color_palette_flags_t get_palette_flags (const void *base,
51 unsigned int palette_index,
52 unsigned int palette_count) const
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];
59 hb_ot_name_id_t get_palette_name_id (const void *base,
60 unsigned int palette_index,
61 unsigned int palette_count) const
63 if (!paletteLabelsZ) return HB_OT_NAME_ID_INVALID;
64 return (base+paletteLabelsZ).as_array (palette_count)[palette_index];
67 hb_ot_name_id_t get_color_name_id (const void *base,
68 unsigned int color_index,
69 unsigned int color_count) const
71 if (!colorLabelsZ) return HB_OT_NAME_ID_INVALID;
72 return (base+colorLabelsZ).as_array (color_count)[color_index];
76 void collect_name_ids (const void *base,
77 unsigned palette_count,
79 const hb_map_t *color_index_map,
80 hb_set_t *nameids_to_retain /* OUT */) const
84 + (base+paletteLabelsZ).as_array (palette_count)
85 | hb_sink (nameids_to_retain)
91 const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
92 for (unsigned i = 0; i < color_count; i++)
94 if (!color_index_map->has (i)) continue;
95 nameids_to_retain->add (colorLabels[i]);
100 bool serialize (hb_serialize_context_t *c,
101 unsigned palette_count,
102 unsigned color_count,
104 const hb_map_t *color_index_map) const
106 TRACE_SERIALIZE (this);
107 auto *out = c->allocate_size<CPALV1Tail> (static_size);
108 if (unlikely (!out)) return_trace (false);
110 out->paletteFlagsZ = 0;
112 out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
114 out->paletteLabelsZ = 0;
116 out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
118 const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
122 for (unsigned i = 0; i < color_count; i++)
124 if (!color_index_map->has (i)) continue;
125 if (!c->copy<NameID> (colorLabels[i]))
128 return_trace (false);
131 c->add_link (out->colorLabelsZ, c->pop_pack ());
136 bool sanitize (hb_sanitize_context_t *c,
138 unsigned int palette_count,
139 unsigned int color_count) const
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)));
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
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. */
164 DEFINE_SIZE_STATIC (12);
167 typedef HBUINT32 BGRAColor;
171 static constexpr hb_tag_t tableTag = HB_OT_TAG_CPAL;
173 bool has_data () const { return numPalettes; }
175 unsigned int get_size () const
176 { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); }
178 unsigned int get_palette_count () const { return numPalettes; }
179 unsigned int get_color_count () const { return numColors; }
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); }
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); }
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); }
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
195 if (unlikely (palette_index >= numPalettes))
197 if (color_count) *color_count = 0;
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,
206 + palette_colors.sub_array (start_offset, color_count)
207 | hb_sink (hb_array (colors, *color_count))
213 void collect_name_ids (const hb_map_t *color_index_map,
214 hb_set_t *nameids_to_retain /* OUT */) const
217 v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain);
221 const CPALV1Tail& v1 () const
223 if (version == 0) return Null (CPALV1Tail);
224 return StructAfter<CPALV1Tail> (*this);
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
235 TRACE_SERIALIZE (this);
237 // TODO(grieger): limit total final size.
239 for (const auto idx : color_record_indices)
241 hb_codepoint_t layer_index = first_color_to_layer_index[idx];
244 new_idx = layer_index * retained_color_indices.get_population ();
245 if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
249 for (unsigned first_color_index : first_color_index_for_layer)
251 for (hb_codepoint_t color_index : retained_color_indices)
253 if (!c->copy<BGRAColor> (color_records[first_color_index + color_index]))
256 return_trace (false);
261 c->add_link (colorRecordsZ, c->pop_pack ());
265 bool subset (hb_subset_context_t *c) const
268 if (!numPalettes) return_trace (false);
270 const hb_map_t *color_index_map = &c->plan->colr_palettes;
271 if (color_index_map->is_empty ()) return_trace (false);
273 hb_set_t retained_color_indices;
274 for (const auto _ : color_index_map->keys ())
276 if (_ == 0xFFFF) continue;
277 retained_color_indices.add (_);
279 if (retained_color_indices.is_empty ()) return_trace (false);
281 auto *out = c->serializer->start_embed (*this);
282 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
285 out->version = version;
286 out->numColors = retained_color_indices.get_population ();
287 out->numPalettes = numPalettes;
289 hb_vector_t<unsigned> first_color_index_for_layer;
290 hb_map_t first_color_to_layer_index;
292 const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
293 for (const auto first_color_record_idx : colorRecordIndices)
295 if (first_color_to_layer_index.has (first_color_record_idx)) continue;
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);
302 out->numColorRecords = first_color_index_for_layer.length
303 * retained_color_indices.get_population ();
305 const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords);
306 if (!out->serialize (c->serializer,
309 first_color_index_for_layer,
310 first_color_to_layer_index,
311 retained_color_indices))
312 return_trace (false);
315 return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
320 bool sanitize (hb_sanitize_context_t *c) const
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)));
330 HBUINT16 version; /* Table version number */
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
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. */
344 DEFINE_SIZE_ARRAY (12, colorRecordIndicesZ);
350 #endif /* OT_COLOR_CPAL_CPAL_HH */