1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Cpal<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.color_record_indices_byte_range().end
11 }
12 fn min_table_bytes(&self) -> &'a [u8] {
13 let range = self.min_byte_range();
14 self.data.as_bytes().get(range).unwrap_or_default()
15 }
16}
17
18impl TopLevelTable for Cpal<'_> {
19 const TAG: Tag = Tag::new(b"CPAL");
21}
22
23impl ReadArgs for Cpal<'_> {
24 type Args = ();
25}
26
27impl<'a> FontRead<'a> for Cpal<'a> {
28 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
29 #[allow(clippy::absurd_extreme_comparisons)]
30 if data.len() < Self::MIN_SIZE {
31 return Err(ReadError::OutOfBounds);
32 }
33 Ok(Self { data })
34 }
35}
36
37#[derive(Clone)]
39pub struct Cpal<'a> {
40 data: FontData<'a>,
41}
42
43#[allow(clippy::needless_lifetimes)]
44impl<'a> Cpal<'a> {
45 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
46 + u16::RAW_BYTE_LEN
47 + u16::RAW_BYTE_LEN
48 + u16::RAW_BYTE_LEN
49 + Offset32::RAW_BYTE_LEN);
50 basic_table_impls!(impl_the_methods);
51
52 pub fn version(&self) -> u16 {
54 let range = self.version_byte_range();
55 self.data.read_at(range.start).ok().unwrap()
56 }
57
58 pub fn num_palette_entries(&self) -> u16 {
60 let range = self.num_palette_entries_byte_range();
61 self.data.read_at(range.start).ok().unwrap()
62 }
63
64 pub fn num_palettes(&self) -> u16 {
66 let range = self.num_palettes_byte_range();
67 self.data.read_at(range.start).ok().unwrap()
68 }
69
70 pub fn num_color_records(&self) -> u16 {
72 let range = self.num_color_records_byte_range();
73 self.data.read_at(range.start).ok().unwrap()
74 }
75
76 pub fn color_records_array_offset(&self) -> Nullable<Offset32> {
79 let range = self.color_records_array_offset_byte_range();
80 self.data.read_at(range.start).ok().unwrap()
81 }
82
83 pub fn color_records_array(&self) -> Option<Result<&'a [ColorRecord], ReadError>> {
85 let data = self.data;
86 let args = self.num_color_records();
87 self.color_records_array_offset()
88 .resolve_with_args(data, args)
89 }
90
91 pub fn color_record_indices(&self) -> &'a [BigEndian<u16>] {
94 let range = self.color_record_indices_byte_range();
95 self.data.read_array(range).ok().unwrap_or_default()
96 }
97
98 pub fn palette_types_array_offset(&self) -> Option<Nullable<Offset32>> {
104 let range = self.palette_types_array_offset_byte_range();
105 (!range.is_empty())
106 .then(|| self.data.read_at(range.start).ok())
107 .flatten()
108 }
109
110 pub fn palette_types_array(&self) -> Option<Result<&'a [BigEndian<PaletteType>], ReadError>> {
112 let data = self.data;
113 let args = self.num_palettes();
114 self.palette_types_array_offset()
115 .map(|x| x.resolve_with_args(data, args))?
116 }
117
118 pub fn palette_labels_array_offset(&self) -> Option<Nullable<Offset32>> {
126 let range = self.palette_labels_array_offset_byte_range();
127 (!range.is_empty())
128 .then(|| self.data.read_at(range.start).ok())
129 .flatten()
130 }
131
132 pub fn palette_labels_array(&self) -> Option<Result<&'a [BigEndian<NameId>], ReadError>> {
134 let data = self.data;
135 let args = self.num_palettes();
136 self.palette_labels_array_offset()
137 .map(|x| x.resolve_with_args(data, args))?
138 }
139
140 pub fn palette_entry_labels_array_offset(&self) -> Option<Nullable<Offset32>> {
150 let range = self.palette_entry_labels_array_offset_byte_range();
151 (!range.is_empty())
152 .then(|| self.data.read_at(range.start).ok())
153 .flatten()
154 }
155
156 pub fn palette_entry_labels_array(&self) -> Option<Result<&'a [BigEndian<NameId>], ReadError>> {
158 let data = self.data;
159 let args = self.num_palette_entries();
160 self.palette_entry_labels_array_offset()
161 .map(|x| x.resolve_with_args(data, args))?
162 }
163
164 pub fn version_byte_range(&self) -> Range<usize> {
165 let start = 0;
166 let end = start + u16::RAW_BYTE_LEN;
167 start..end
168 }
169
170 pub fn num_palette_entries_byte_range(&self) -> Range<usize> {
171 let start = self.version_byte_range().end;
172 let end = start + u16::RAW_BYTE_LEN;
173 start..end
174 }
175
176 pub fn num_palettes_byte_range(&self) -> Range<usize> {
177 let start = self.num_palette_entries_byte_range().end;
178 let end = start + u16::RAW_BYTE_LEN;
179 start..end
180 }
181
182 pub fn num_color_records_byte_range(&self) -> Range<usize> {
183 let start = self.num_palettes_byte_range().end;
184 let end = start + u16::RAW_BYTE_LEN;
185 start..end
186 }
187
188 pub fn color_records_array_offset_byte_range(&self) -> Range<usize> {
189 let start = self.num_color_records_byte_range().end;
190 let end = start + Offset32::RAW_BYTE_LEN;
191 start..end
192 }
193
194 pub fn color_record_indices_byte_range(&self) -> Range<usize> {
195 let num_palettes = self.num_palettes();
196 let start = self.color_records_array_offset_byte_range().end;
197 let end = start + (transforms::to_usize(num_palettes)).saturating_mul(u16::RAW_BYTE_LEN);
198 start..end
199 }
200
201 pub fn palette_types_array_offset_byte_range(&self) -> Range<usize> {
202 let start = self.color_record_indices_byte_range().end;
203 let end = if self.version().compatible(1u16) {
204 start + Offset32::RAW_BYTE_LEN
205 } else {
206 start
207 };
208 start..end
209 }
210
211 pub fn palette_labels_array_offset_byte_range(&self) -> Range<usize> {
212 let start = self.palette_types_array_offset_byte_range().end;
213 let end = if self.version().compatible(1u16) {
214 start + Offset32::RAW_BYTE_LEN
215 } else {
216 start
217 };
218 start..end
219 }
220
221 pub fn palette_entry_labels_array_offset_byte_range(&self) -> Range<usize> {
222 let start = self.palette_labels_array_offset_byte_range().end;
223 let end = if self.version().compatible(1u16) {
224 start + Offset32::RAW_BYTE_LEN
225 } else {
226 start
227 };
228 start..end
229 }
230}
231
232const _: () = assert!(FontData::default_data_long_enough(Cpal::MIN_SIZE));
233
234impl Default for Cpal<'_> {
235 fn default() -> Self {
236 Self {
237 data: FontData::default_table_data(),
238 }
239 }
240}
241
242#[cfg(feature = "experimental_traverse")]
243impl<'a> SomeTable<'a> for Cpal<'a> {
244 fn type_name(&self) -> &str {
245 "Cpal"
246 }
247 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
248 match idx {
249 0usize => Some(Field::new("version", self.version())),
250 1usize => Some(Field::new(
251 "num_palette_entries",
252 self.num_palette_entries(),
253 )),
254 2usize => Some(Field::new("num_palettes", self.num_palettes())),
255 3usize => Some(Field::new("num_color_records", self.num_color_records())),
256 4usize => Some(Field::new(
257 "color_records_array_offset",
258 traversal::FieldType::offset_to_array_of_records(
259 self.color_records_array_offset(),
260 self.color_records_array(),
261 stringify!(ColorRecord),
262 self.offset_data(),
263 ),
264 )),
265 5usize => Some(Field::new(
266 "color_record_indices",
267 self.color_record_indices(),
268 )),
269 6usize if self.version().compatible(1u16) => Some(Field::new(
270 "palette_types_array_offset",
271 FieldType::offset_to_array_of_scalars(
272 self.palette_types_array_offset().unwrap(),
273 self.palette_types_array(),
274 ),
275 )),
276 7usize if self.version().compatible(1u16) => Some(Field::new(
277 "palette_labels_array_offset",
278 FieldType::offset_to_array_of_scalars(
279 self.palette_labels_array_offset().unwrap(),
280 self.palette_labels_array(),
281 ),
282 )),
283 8usize if self.version().compatible(1u16) => Some(Field::new(
284 "palette_entry_labels_array_offset",
285 FieldType::offset_to_array_of_scalars(
286 self.palette_entry_labels_array_offset().unwrap(),
287 self.palette_entry_labels_array(),
288 ),
289 )),
290 _ => None,
291 }
292 }
293}
294
295#[cfg(feature = "experimental_traverse")]
296#[allow(clippy::needless_lifetimes)]
297impl<'a> std::fmt::Debug for Cpal<'a> {
298 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
299 (self as &dyn SomeTable<'a>).fmt(f)
300 }
301}
302
303#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
305#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
306#[repr(transparent)]
307pub struct PaletteType {
308 bits: u32,
309}
310
311impl PaletteType {
312 pub const USABLE_WITH_LIGHT_BACKGROUND: Self = Self { bits: 0x0001 };
314
315 pub const USABLE_WITH_DARK_BACKGROUND: Self = Self { bits: 0x0002 };
317}
318
319impl PaletteType {
320 #[inline]
322 pub const fn empty() -> Self {
323 Self { bits: 0 }
324 }
325
326 #[inline]
328 pub const fn all() -> Self {
329 Self {
330 bits: Self::USABLE_WITH_LIGHT_BACKGROUND.bits | Self::USABLE_WITH_DARK_BACKGROUND.bits,
331 }
332 }
333
334 #[inline]
336 pub const fn bits(&self) -> u32 {
337 self.bits
338 }
339
340 #[inline]
343 pub const fn from_bits(bits: u32) -> Option<Self> {
344 if (bits & !Self::all().bits()) == 0 {
345 Some(Self { bits })
346 } else {
347 None
348 }
349 }
350
351 #[inline]
354 pub const fn from_bits_truncate(bits: u32) -> Self {
355 Self {
356 bits: bits & Self::all().bits,
357 }
358 }
359
360 #[inline]
362 pub const fn is_empty(&self) -> bool {
363 self.bits() == Self::empty().bits()
364 }
365
366 #[inline]
368 pub const fn intersects(&self, other: Self) -> bool {
369 !(Self {
370 bits: self.bits & other.bits,
371 })
372 .is_empty()
373 }
374
375 #[inline]
377 pub const fn contains(&self, other: Self) -> bool {
378 (self.bits & other.bits) == other.bits
379 }
380
381 #[inline]
383 pub fn insert(&mut self, other: Self) {
384 self.bits |= other.bits;
385 }
386
387 #[inline]
389 pub fn remove(&mut self, other: Self) {
390 self.bits &= !other.bits;
391 }
392
393 #[inline]
395 pub fn toggle(&mut self, other: Self) {
396 self.bits ^= other.bits;
397 }
398
399 #[inline]
410 #[must_use]
411 pub const fn intersection(self, other: Self) -> Self {
412 Self {
413 bits: self.bits & other.bits,
414 }
415 }
416
417 #[inline]
428 #[must_use]
429 pub const fn union(self, other: Self) -> Self {
430 Self {
431 bits: self.bits | other.bits,
432 }
433 }
434
435 #[inline]
448 #[must_use]
449 pub const fn difference(self, other: Self) -> Self {
450 Self {
451 bits: self.bits & !other.bits,
452 }
453 }
454}
455
456impl std::ops::BitOr for PaletteType {
457 type Output = Self;
458
459 #[inline]
461 fn bitor(self, other: PaletteType) -> Self {
462 Self {
463 bits: self.bits | other.bits,
464 }
465 }
466}
467
468impl std::ops::BitOrAssign for PaletteType {
469 #[inline]
471 fn bitor_assign(&mut self, other: Self) {
472 self.bits |= other.bits;
473 }
474}
475
476impl std::ops::BitXor for PaletteType {
477 type Output = Self;
478
479 #[inline]
481 fn bitxor(self, other: Self) -> Self {
482 Self {
483 bits: self.bits ^ other.bits,
484 }
485 }
486}
487
488impl std::ops::BitXorAssign for PaletteType {
489 #[inline]
491 fn bitxor_assign(&mut self, other: Self) {
492 self.bits ^= other.bits;
493 }
494}
495
496impl std::ops::BitAnd for PaletteType {
497 type Output = Self;
498
499 #[inline]
501 fn bitand(self, other: Self) -> Self {
502 Self {
503 bits: self.bits & other.bits,
504 }
505 }
506}
507
508impl std::ops::BitAndAssign for PaletteType {
509 #[inline]
511 fn bitand_assign(&mut self, other: Self) {
512 self.bits &= other.bits;
513 }
514}
515
516impl std::ops::Sub for PaletteType {
517 type Output = Self;
518
519 #[inline]
521 fn sub(self, other: Self) -> Self {
522 Self {
523 bits: self.bits & !other.bits,
524 }
525 }
526}
527
528impl std::ops::SubAssign for PaletteType {
529 #[inline]
531 fn sub_assign(&mut self, other: Self) {
532 self.bits &= !other.bits;
533 }
534}
535
536impl std::ops::Not for PaletteType {
537 type Output = Self;
538
539 #[inline]
541 fn not(self) -> Self {
542 Self { bits: !self.bits } & Self::all()
543 }
544}
545
546impl std::fmt::Debug for PaletteType {
547 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
548 let members: &[(&str, Self)] = &[
549 (
550 "USABLE_WITH_LIGHT_BACKGROUND",
551 Self::USABLE_WITH_LIGHT_BACKGROUND,
552 ),
553 (
554 "USABLE_WITH_DARK_BACKGROUND",
555 Self::USABLE_WITH_DARK_BACKGROUND,
556 ),
557 ];
558 let mut first = true;
559 for (name, value) in members {
560 if self.contains(*value) {
561 if !first {
562 f.write_str(" | ")?;
563 }
564 first = false;
565 f.write_str(name)?;
566 }
567 }
568 if first {
569 f.write_str("(empty)")?;
570 }
571 Ok(())
572 }
573}
574
575impl std::fmt::Binary for PaletteType {
576 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
577 std::fmt::Binary::fmt(&self.bits, f)
578 }
579}
580
581impl std::fmt::Octal for PaletteType {
582 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
583 std::fmt::Octal::fmt(&self.bits, f)
584 }
585}
586
587impl std::fmt::LowerHex for PaletteType {
588 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
589 std::fmt::LowerHex::fmt(&self.bits, f)
590 }
591}
592
593impl std::fmt::UpperHex for PaletteType {
594 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
595 std::fmt::UpperHex::fmt(&self.bits, f)
596 }
597}
598
599impl font_types::Scalar for PaletteType {
600 type Raw = <u32 as font_types::Scalar>::Raw;
601 fn to_raw(self) -> Self::Raw {
602 self.bits().to_raw()
603 }
604 fn from_raw(raw: Self::Raw) -> Self {
605 let t = <u32>::from_raw(raw);
606 Self::from_bits_truncate(t)
607 }
608}
609
610#[cfg(feature = "experimental_traverse")]
611impl<'a> From<PaletteType> for FieldType<'a> {
612 fn from(src: PaletteType) -> FieldType<'a> {
613 src.bits().into()
614 }
615}
616
617#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
621#[repr(C)]
622#[repr(packed)]
623pub struct ColorRecord {
624 pub blue: u8,
626 pub green: u8,
628 pub red: u8,
630 pub alpha: u8,
632}
633
634impl ColorRecord {
635 pub fn blue(&self) -> u8 {
637 self.blue
638 }
639
640 pub fn green(&self) -> u8 {
642 self.green
643 }
644
645 pub fn red(&self) -> u8 {
647 self.red
648 }
649
650 pub fn alpha(&self) -> u8 {
652 self.alpha
653 }
654}
655
656impl FixedSize for ColorRecord {
657 const RAW_BYTE_LEN: usize =
658 u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
659}
660
661#[cfg(feature = "experimental_traverse")]
662impl<'a> SomeRecord<'a> for ColorRecord {
663 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
664 RecordResolver {
665 name: "ColorRecord",
666 get_field: Box::new(move |idx, _data| match idx {
667 0usize => Some(Field::new("blue", self.blue())),
668 1usize => Some(Field::new("green", self.green())),
669 2usize => Some(Field::new("red", self.red())),
670 3usize => Some(Field::new("alpha", self.alpha())),
671 _ => None,
672 }),
673 data,
674 }
675 }
676}