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 HB_OT_COLOR_CPAL_TABLE_HH
29 #define HB_OT_COLOR_CPAL_TABLE_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 bool serialize (hb_serialize_context_t *c,
77 unsigned palette_count,
80 const hb_map_t *color_index_map) const
82 TRACE_SERIALIZE (this);
83 auto *out = c->allocate_size<CPALV1Tail> (static_size);
84 if (unlikely (!out)) return_trace (false);
86 out->paletteFlagsZ = 0;
88 out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
90 out->paletteLabelsZ = 0;
92 out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
94 const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
98 for (const auto _ : colorLabels)
100 if (!color_index_map->has (_)) continue;
101 NameID new_color_idx;
102 new_color_idx = color_index_map->get (_);
103 if (!c->copy<NameID> (new_color_idx))
106 return_trace (false);
109 c->add_link (out->colorLabelsZ, c->pop_pack ());
114 bool sanitize (hb_sanitize_context_t *c,
116 unsigned int palette_count,
117 unsigned int color_count) const
119 TRACE_SANITIZE (this);
120 return_trace (c->check_struct (this) &&
121 (!paletteFlagsZ || (base+paletteFlagsZ).sanitize (c, palette_count)) &&
122 (!paletteLabelsZ || (base+paletteLabelsZ).sanitize (c, palette_count)) &&
123 (!colorLabelsZ || (base+colorLabelsZ).sanitize (c, color_count)));
127 // TODO(garretrieger): these offsets can hold nulls so we should not be using non-null offsets
128 // here. Currently they are needed since UnsizedArrayOf doesn't define null_size
129 NNOffset32To<UnsizedArrayOf<HBUINT32>>
130 paletteFlagsZ; /* Offset from the beginning of CPAL table to
131 * the Palette Type Array. Set to 0 if no array
133 NNOffset32To<UnsizedArrayOf<NameID>>
134 paletteLabelsZ; /* Offset from the beginning of CPAL table to
135 * the palette labels array. Set to 0 if no
136 * array is provided. */
137 NNOffset32To<UnsizedArrayOf<NameID>>
138 colorLabelsZ; /* Offset from the beginning of CPAL table to
139 * the color labels array. Set to 0
140 * if no array is provided. */
142 DEFINE_SIZE_STATIC (12);
145 typedef HBUINT32 BGRAColor;
149 static constexpr hb_tag_t tableTag = HB_OT_TAG_CPAL;
151 bool has_data () const { return numPalettes; }
153 unsigned int get_size () const
154 { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); }
156 unsigned int get_palette_count () const { return numPalettes; }
157 unsigned int get_color_count () const { return numColors; }
159 hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette_index) const
160 { return v1 ().get_palette_flags (this, palette_index, numPalettes); }
162 hb_ot_name_id_t get_palette_name_id (unsigned int palette_index) const
163 { return v1 ().get_palette_name_id (this, palette_index, numPalettes); }
165 hb_ot_name_id_t get_color_name_id (unsigned int color_index) const
166 { return v1 ().get_color_name_id (this, color_index, numColors); }
168 unsigned int get_palette_colors (unsigned int palette_index,
169 unsigned int start_offset,
170 unsigned int *color_count, /* IN/OUT. May be NULL. */
171 hb_color_t *colors /* OUT. May be NULL. */) const
173 if (unlikely (palette_index >= numPalettes))
175 if (color_count) *color_count = 0;
178 unsigned int start_index = colorRecordIndicesZ[palette_index];
179 hb_array_t<const BGRAColor> all_colors ((this+colorRecordsZ).arrayZ, numColorRecords);
180 hb_array_t<const BGRAColor> palette_colors = all_colors.sub_array (start_index,
184 + palette_colors.sub_array (start_offset, color_count)
185 | hb_sink (hb_array (colors, *color_count))
192 const CPALV1Tail& v1 () const
194 if (version == 0) return Null (CPALV1Tail);
195 return StructAfter<CPALV1Tail> (*this);
199 bool serialize (hb_serialize_context_t *c,
200 const hb_array_t<const BGRAColor> &color_records,
201 const hb_array_t<const HBUINT16> &color_record_indices,
202 const hb_map_t &color_record_index_map,
203 const hb_set_t &retained_color_record_indices) const
205 TRACE_SERIALIZE (this);
207 for (const auto idx : color_record_indices)
210 if (idx == 0) new_idx = 0;
211 else new_idx = color_record_index_map.get (idx);
212 if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
216 for (const auto _ : retained_color_record_indices.iter ())
218 if (!c->copy<BGRAColor> (color_records[_]))
221 return_trace (false);
224 c->add_link (colorRecordsZ, c->pop_pack ());
228 bool subset (hb_subset_context_t *c) const
231 const hb_map_t *color_index_map = c->plan->colr_palettes;
232 if (color_index_map->is_empty ()) return_trace (false);
234 hb_set_t retained_color_indices;
235 for (const auto _ : color_index_map->keys ())
237 if (_ == 0xFFFF) continue;
238 retained_color_indices.add (_);
240 if (retained_color_indices.is_empty ()) return_trace (false);
242 auto *out = c->serializer->start_embed (*this);
243 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
245 out->version = version;
246 out->numColors = retained_color_indices.get_population ();
247 out->numPalettes = numPalettes;
249 const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
250 hb_map_t color_record_index_map;
251 hb_set_t retained_color_record_indices;
253 unsigned record_count = 0;
254 for (const auto first_color_record_idx : colorRecordIndices)
256 for (unsigned retained_color_idx : retained_color_indices.iter ())
258 unsigned color_record_idx = first_color_record_idx + retained_color_idx;
259 if (color_record_index_map.has (color_record_idx)) continue;
260 color_record_index_map.set (color_record_idx, record_count);
261 retained_color_record_indices.add (color_record_idx);
266 out->numColorRecords = record_count;
267 const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords);
268 if (!out->serialize (c->serializer, color_records, colorRecordIndices, color_record_index_map, retained_color_record_indices))
269 return_trace (false);
272 return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
277 bool sanitize (hb_sanitize_context_t *c) const
279 TRACE_SANITIZE (this);
280 return_trace (c->check_struct (this) &&
281 (this+colorRecordsZ).sanitize (c, numColorRecords) &&
282 colorRecordIndicesZ.sanitize (c, numPalettes) &&
283 (version == 0 || v1 ().sanitize (c, this, numPalettes, numColors)));
287 HBUINT16 version; /* Table version number */
289 HBUINT16 numColors; /* Number of colors in each palette. */
290 HBUINT16 numPalettes; /* Number of palettes in the table. */
291 HBUINT16 numColorRecords; /* Total number of color records, combined for
293 NNOffset32To<UnsizedArrayOf<BGRAColor>>
294 colorRecordsZ; /* Offset from the beginning of CPAL table to
295 * the first ColorRecord. */
296 UnsizedArrayOf<HBUINT16>
297 colorRecordIndicesZ; /* Index of each palette’s first color record in
298 * the combined color record array. */
301 DEFINE_SIZE_ARRAY (12, colorRecordIndicesZ);
307 #endif /* HB_OT_COLOR_CPAL_TABLE_HH */