1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8#[derive(Debug, Clone, Copy)]
10#[doc(hidden)]
11pub struct CpalMarker {
12 color_record_indices_byte_len: usize,
13 palette_types_array_offset_byte_start: Option<usize>,
14 palette_labels_array_offset_byte_start: Option<usize>,
15 palette_entry_labels_array_offset_byte_start: Option<usize>,
16}
17
18impl CpalMarker {
19 pub fn version_byte_range(&self) -> Range<usize> {
20 let start = 0;
21 start..start + u16::RAW_BYTE_LEN
22 }
23
24 pub fn num_palette_entries_byte_range(&self) -> Range<usize> {
25 let start = self.version_byte_range().end;
26 start..start + u16::RAW_BYTE_LEN
27 }
28
29 pub fn num_palettes_byte_range(&self) -> Range<usize> {
30 let start = self.num_palette_entries_byte_range().end;
31 start..start + u16::RAW_BYTE_LEN
32 }
33
34 pub fn num_color_records_byte_range(&self) -> Range<usize> {
35 let start = self.num_palettes_byte_range().end;
36 start..start + u16::RAW_BYTE_LEN
37 }
38
39 pub fn color_records_array_offset_byte_range(&self) -> Range<usize> {
40 let start = self.num_color_records_byte_range().end;
41 start..start + Offset32::RAW_BYTE_LEN
42 }
43
44 pub fn color_record_indices_byte_range(&self) -> Range<usize> {
45 let start = self.color_records_array_offset_byte_range().end;
46 start..start + self.color_record_indices_byte_len
47 }
48
49 pub fn palette_types_array_offset_byte_range(&self) -> Option<Range<usize>> {
50 let start = self.palette_types_array_offset_byte_start?;
51 Some(start..start + Offset32::RAW_BYTE_LEN)
52 }
53
54 pub fn palette_labels_array_offset_byte_range(&self) -> Option<Range<usize>> {
55 let start = self.palette_labels_array_offset_byte_start?;
56 Some(start..start + Offset32::RAW_BYTE_LEN)
57 }
58
59 pub fn palette_entry_labels_array_offset_byte_range(&self) -> Option<Range<usize>> {
60 let start = self.palette_entry_labels_array_offset_byte_start?;
61 Some(start..start + Offset32::RAW_BYTE_LEN)
62 }
63}
64
65impl MinByteRange for CpalMarker {
66 fn min_byte_range(&self) -> Range<usize> {
67 0..self.color_record_indices_byte_range().end
68 }
69}
70
71impl TopLevelTable for Cpal<'_> {
72 const TAG: Tag = Tag::new(b"CPAL");
74}
75
76impl<'a> FontRead<'a> for Cpal<'a> {
77 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
78 let mut cursor = data.cursor();
79 let version: u16 = cursor.read()?;
80 cursor.advance::<u16>();
81 let num_palettes: u16 = cursor.read()?;
82 cursor.advance::<u16>();
83 cursor.advance::<Offset32>();
84 let color_record_indices_byte_len = (num_palettes as usize)
85 .checked_mul(u16::RAW_BYTE_LEN)
86 .ok_or(ReadError::OutOfBounds)?;
87 cursor.advance_by(color_record_indices_byte_len);
88 let palette_types_array_offset_byte_start = version
89 .compatible(1u16)
90 .then(|| cursor.position())
91 .transpose()?;
92 version
93 .compatible(1u16)
94 .then(|| cursor.advance::<Offset32>());
95 let palette_labels_array_offset_byte_start = version
96 .compatible(1u16)
97 .then(|| cursor.position())
98 .transpose()?;
99 version
100 .compatible(1u16)
101 .then(|| cursor.advance::<Offset32>());
102 let palette_entry_labels_array_offset_byte_start = version
103 .compatible(1u16)
104 .then(|| cursor.position())
105 .transpose()?;
106 version
107 .compatible(1u16)
108 .then(|| cursor.advance::<Offset32>());
109 cursor.finish(CpalMarker {
110 color_record_indices_byte_len,
111 palette_types_array_offset_byte_start,
112 palette_labels_array_offset_byte_start,
113 palette_entry_labels_array_offset_byte_start,
114 })
115 }
116}
117
118pub type Cpal<'a> = TableRef<'a, CpalMarker>;
120
121#[allow(clippy::needless_lifetimes)]
122impl<'a> Cpal<'a> {
123 pub fn version(&self) -> u16 {
125 let range = self.shape.version_byte_range();
126 self.data.read_at(range.start).unwrap()
127 }
128
129 pub fn num_palette_entries(&self) -> u16 {
131 let range = self.shape.num_palette_entries_byte_range();
132 self.data.read_at(range.start).unwrap()
133 }
134
135 pub fn num_palettes(&self) -> u16 {
137 let range = self.shape.num_palettes_byte_range();
138 self.data.read_at(range.start).unwrap()
139 }
140
141 pub fn num_color_records(&self) -> u16 {
143 let range = self.shape.num_color_records_byte_range();
144 self.data.read_at(range.start).unwrap()
145 }
146
147 pub fn color_records_array_offset(&self) -> Nullable<Offset32> {
150 let range = self.shape.color_records_array_offset_byte_range();
151 self.data.read_at(range.start).unwrap()
152 }
153
154 pub fn color_records_array(&self) -> Option<Result<&'a [ColorRecord], ReadError>> {
156 let data = self.data;
157 let args = self.num_color_records();
158 self.color_records_array_offset()
159 .resolve_with_args(data, &args)
160 }
161
162 pub fn color_record_indices(&self) -> &'a [BigEndian<u16>] {
165 let range = self.shape.color_record_indices_byte_range();
166 self.data.read_array(range).unwrap()
167 }
168
169 pub fn palette_types_array_offset(&self) -> Option<Nullable<Offset32>> {
175 let range = self.shape.palette_types_array_offset_byte_range()?;
176 Some(self.data.read_at(range.start).unwrap())
177 }
178
179 pub fn palette_types_array(&self) -> Option<Result<&'a [BigEndian<PaletteType>], ReadError>> {
181 let data = self.data;
182 let args = self.num_palettes();
183 self.palette_types_array_offset()
184 .map(|x| x.resolve_with_args(data, &args))?
185 }
186
187 pub fn palette_labels_array_offset(&self) -> Option<Nullable<Offset32>> {
195 let range = self.shape.palette_labels_array_offset_byte_range()?;
196 Some(self.data.read_at(range.start).unwrap())
197 }
198
199 pub fn palette_labels_array(&self) -> Option<Result<&'a [BigEndian<u16>], ReadError>> {
201 let data = self.data;
202 let args = self.num_palettes();
203 self.palette_labels_array_offset()
204 .map(|x| x.resolve_with_args(data, &args))?
205 }
206
207 pub fn palette_entry_labels_array_offset(&self) -> Option<Nullable<Offset32>> {
217 let range = self.shape.palette_entry_labels_array_offset_byte_range()?;
218 Some(self.data.read_at(range.start).unwrap())
219 }
220
221 pub fn palette_entry_labels_array(&self) -> Option<Result<&'a [BigEndian<NameId>], ReadError>> {
223 let data = self.data;
224 let args = self.num_palette_entries();
225 self.palette_entry_labels_array_offset()
226 .map(|x| x.resolve_with_args(data, &args))?
227 }
228}
229
230#[cfg(feature = "experimental_traverse")]
231impl<'a> SomeTable<'a> for Cpal<'a> {
232 fn type_name(&self) -> &str {
233 "Cpal"
234 }
235 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
236 let version = self.version();
237 match idx {
238 0usize => Some(Field::new("version", self.version())),
239 1usize => Some(Field::new(
240 "num_palette_entries",
241 self.num_palette_entries(),
242 )),
243 2usize => Some(Field::new("num_palettes", self.num_palettes())),
244 3usize => Some(Field::new("num_color_records", self.num_color_records())),
245 4usize => Some(Field::new(
246 "color_records_array_offset",
247 traversal::FieldType::offset_to_array_of_records(
248 self.color_records_array_offset(),
249 self.color_records_array(),
250 stringify!(ColorRecord),
251 self.offset_data(),
252 ),
253 )),
254 5usize => Some(Field::new(
255 "color_record_indices",
256 self.color_record_indices(),
257 )),
258 6usize if version.compatible(1u16) => Some(Field::new(
259 "palette_types_array_offset",
260 FieldType::offset_to_array_of_scalars(
261 self.palette_types_array_offset().unwrap(),
262 self.palette_types_array(),
263 ),
264 )),
265 7usize if version.compatible(1u16) => Some(Field::new(
266 "palette_labels_array_offset",
267 FieldType::offset_to_array_of_scalars(
268 self.palette_labels_array_offset().unwrap(),
269 self.palette_labels_array(),
270 ),
271 )),
272 8usize if version.compatible(1u16) => Some(Field::new(
273 "palette_entry_labels_array_offset",
274 FieldType::offset_to_array_of_scalars(
275 self.palette_entry_labels_array_offset().unwrap(),
276 self.palette_entry_labels_array(),
277 ),
278 )),
279 _ => None,
280 }
281 }
282}
283
284#[cfg(feature = "experimental_traverse")]
285#[allow(clippy::needless_lifetimes)]
286impl<'a> std::fmt::Debug for Cpal<'a> {
287 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288 (self as &dyn SomeTable<'a>).fmt(f)
289 }
290}
291
292#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
294#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
295#[repr(transparent)]
296pub struct PaletteType {
297 bits: u32,
298}
299
300impl PaletteType {
301 pub const USABLE_WITH_LIGHT_BACKGROUND: Self = Self { bits: 0x0001 };
303
304 pub const USABLE_WITH_DARK_BACKGROUND: Self = Self { bits: 0x0002 };
306}
307
308impl PaletteType {
309 #[inline]
311 pub const fn empty() -> Self {
312 Self { bits: 0 }
313 }
314
315 #[inline]
317 pub const fn all() -> Self {
318 Self {
319 bits: Self::USABLE_WITH_LIGHT_BACKGROUND.bits | Self::USABLE_WITH_DARK_BACKGROUND.bits,
320 }
321 }
322
323 #[inline]
325 pub const fn bits(&self) -> u32 {
326 self.bits
327 }
328
329 #[inline]
332 pub const fn from_bits(bits: u32) -> Option<Self> {
333 if (bits & !Self::all().bits()) == 0 {
334 Some(Self { bits })
335 } else {
336 None
337 }
338 }
339
340 #[inline]
343 pub const fn from_bits_truncate(bits: u32) -> Self {
344 Self {
345 bits: bits & Self::all().bits,
346 }
347 }
348
349 #[inline]
351 pub const fn is_empty(&self) -> bool {
352 self.bits() == Self::empty().bits()
353 }
354
355 #[inline]
357 pub const fn intersects(&self, other: Self) -> bool {
358 !(Self {
359 bits: self.bits & other.bits,
360 })
361 .is_empty()
362 }
363
364 #[inline]
366 pub const fn contains(&self, other: Self) -> bool {
367 (self.bits & other.bits) == other.bits
368 }
369
370 #[inline]
372 pub fn insert(&mut self, other: Self) {
373 self.bits |= other.bits;
374 }
375
376 #[inline]
378 pub fn remove(&mut self, other: Self) {
379 self.bits &= !other.bits;
380 }
381
382 #[inline]
384 pub fn toggle(&mut self, other: Self) {
385 self.bits ^= other.bits;
386 }
387
388 #[inline]
399 #[must_use]
400 pub const fn intersection(self, other: Self) -> Self {
401 Self {
402 bits: self.bits & other.bits,
403 }
404 }
405
406 #[inline]
417 #[must_use]
418 pub const fn union(self, other: Self) -> Self {
419 Self {
420 bits: self.bits | other.bits,
421 }
422 }
423
424 #[inline]
437 #[must_use]
438 pub const fn difference(self, other: Self) -> Self {
439 Self {
440 bits: self.bits & !other.bits,
441 }
442 }
443}
444
445impl std::ops::BitOr for PaletteType {
446 type Output = Self;
447
448 #[inline]
450 fn bitor(self, other: PaletteType) -> Self {
451 Self {
452 bits: self.bits | other.bits,
453 }
454 }
455}
456
457impl std::ops::BitOrAssign for PaletteType {
458 #[inline]
460 fn bitor_assign(&mut self, other: Self) {
461 self.bits |= other.bits;
462 }
463}
464
465impl std::ops::BitXor for PaletteType {
466 type Output = Self;
467
468 #[inline]
470 fn bitxor(self, other: Self) -> Self {
471 Self {
472 bits: self.bits ^ other.bits,
473 }
474 }
475}
476
477impl std::ops::BitXorAssign for PaletteType {
478 #[inline]
480 fn bitxor_assign(&mut self, other: Self) {
481 self.bits ^= other.bits;
482 }
483}
484
485impl std::ops::BitAnd for PaletteType {
486 type Output = Self;
487
488 #[inline]
490 fn bitand(self, other: Self) -> Self {
491 Self {
492 bits: self.bits & other.bits,
493 }
494 }
495}
496
497impl std::ops::BitAndAssign for PaletteType {
498 #[inline]
500 fn bitand_assign(&mut self, other: Self) {
501 self.bits &= other.bits;
502 }
503}
504
505impl std::ops::Sub for PaletteType {
506 type Output = Self;
507
508 #[inline]
510 fn sub(self, other: Self) -> Self {
511 Self {
512 bits: self.bits & !other.bits,
513 }
514 }
515}
516
517impl std::ops::SubAssign for PaletteType {
518 #[inline]
520 fn sub_assign(&mut self, other: Self) {
521 self.bits &= !other.bits;
522 }
523}
524
525impl std::ops::Not for PaletteType {
526 type Output = Self;
527
528 #[inline]
530 fn not(self) -> Self {
531 Self { bits: !self.bits } & Self::all()
532 }
533}
534
535impl std::fmt::Debug for PaletteType {
536 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
537 let members: &[(&str, Self)] = &[
538 (
539 "USABLE_WITH_LIGHT_BACKGROUND",
540 Self::USABLE_WITH_LIGHT_BACKGROUND,
541 ),
542 (
543 "USABLE_WITH_DARK_BACKGROUND",
544 Self::USABLE_WITH_DARK_BACKGROUND,
545 ),
546 ];
547 let mut first = true;
548 for (name, value) in members {
549 if self.contains(*value) {
550 if !first {
551 f.write_str(" | ")?;
552 }
553 first = false;
554 f.write_str(name)?;
555 }
556 }
557 if first {
558 f.write_str("(empty)")?;
559 }
560 Ok(())
561 }
562}
563
564impl std::fmt::Binary for PaletteType {
565 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
566 std::fmt::Binary::fmt(&self.bits, f)
567 }
568}
569
570impl std::fmt::Octal for PaletteType {
571 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
572 std::fmt::Octal::fmt(&self.bits, f)
573 }
574}
575
576impl std::fmt::LowerHex for PaletteType {
577 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
578 std::fmt::LowerHex::fmt(&self.bits, f)
579 }
580}
581
582impl std::fmt::UpperHex for PaletteType {
583 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
584 std::fmt::UpperHex::fmt(&self.bits, f)
585 }
586}
587
588impl font_types::Scalar for PaletteType {
589 type Raw = <u32 as font_types::Scalar>::Raw;
590 fn to_raw(self) -> Self::Raw {
591 self.bits().to_raw()
592 }
593 fn from_raw(raw: Self::Raw) -> Self {
594 let t = <u32>::from_raw(raw);
595 Self::from_bits_truncate(t)
596 }
597}
598
599#[cfg(feature = "experimental_traverse")]
600impl<'a> From<PaletteType> for FieldType<'a> {
601 fn from(src: PaletteType) -> FieldType<'a> {
602 src.bits().into()
603 }
604}
605
606#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
608#[repr(C)]
609#[repr(packed)]
610pub struct ColorRecord {
611 pub blue: u8,
613 pub green: u8,
615 pub red: u8,
617 pub alpha: u8,
619}
620
621impl ColorRecord {
622 pub fn blue(&self) -> u8 {
624 self.blue
625 }
626
627 pub fn green(&self) -> u8 {
629 self.green
630 }
631
632 pub fn red(&self) -> u8 {
634 self.red
635 }
636
637 pub fn alpha(&self) -> u8 {
639 self.alpha
640 }
641}
642
643impl FixedSize for ColorRecord {
644 const RAW_BYTE_LEN: usize =
645 u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
646}
647
648#[cfg(feature = "experimental_traverse")]
649impl<'a> SomeRecord<'a> for ColorRecord {
650 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
651 RecordResolver {
652 name: "ColorRecord",
653 get_field: Box::new(move |idx, _data| match idx {
654 0usize => Some(Field::new("blue", self.blue())),
655 1usize => Some(Field::new("green", self.green())),
656 2usize => Some(Field::new("red", self.red())),
657 3usize => Some(Field::new("alpha", self.alpha())),
658 _ => None,
659 }),
660 data,
661 }
662 }
663}