Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add strongly typed PaletteType flags to CPAL #643

Merged
merged 1 commit into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion font-codegen/src/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,11 @@ impl Parse for BitFlags {
let docs = get_optional_docs(input)?;
let _kw = input.parse::<kw::flags>()?;
let typ = input.parse::<syn::Ident>()?;
validate_ident(&typ, &["u8", "u16"], "allowed bitflag types: u8, u16")?;
validate_ident(
&typ,
&["u8", "u16", "u32"],
"allowed bitflag types: u8, u16, u32",
)?;
let name = input.parse::<syn::Ident>()?;

let content;
Expand Down
315 changes: 314 additions & 1 deletion read-fonts/generated/generated_cpal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl<'a> Cpal<'a> {
}

/// Attempt to resolve [`palette_types_array_offset`][Self::palette_types_array_offset].
pub fn palette_types_array(&self) -> Option<Result<&'a [BigEndian<u32>], ReadError>> {
pub fn palette_types_array(&self) -> Option<Result<&'a [BigEndian<PaletteType>], ReadError>> {
let data = self.data;
let args = self.num_palettes();
self.palette_types_array_offset()
Expand Down Expand Up @@ -265,6 +265,319 @@ impl<'a> std::fmt::Debug for Cpal<'a> {
}
}

/// The [PaletteType](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal#palette-type-array) flags.
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PaletteType {
bits: u32,
}

impl PaletteType {
/// Bit 0: palette is appropriate to use when displaying the font on a light background such as white.
pub const USABLE_WITH_LIGHT_BACKGROUND: Self = Self { bits: 0x0001 };

/// Bit 1: palette is appropriate to use when displaying the font on a dark background such as black.
pub const USABLE_WITH_DARK_BACKGROUND: Self = Self { bits: 0x0002 };
}

impl PaletteType {
/// Returns an empty set of flags.
#[inline]
pub const fn empty() -> Self {
Self { bits: 0 }
}

/// Returns the set containing all flags.
#[inline]
pub const fn all() -> Self {
Self {
bits: Self::USABLE_WITH_LIGHT_BACKGROUND.bits | Self::USABLE_WITH_DARK_BACKGROUND.bits,
}
}

/// Returns the raw value of the flags currently stored.
#[inline]
pub const fn bits(&self) -> u32 {
self.bits
}

/// Convert from underlying bit representation, unless that
/// representation contains bits that do not correspond to a flag.
#[inline]
pub const fn from_bits(bits: u32) -> Option<Self> {
if (bits & !Self::all().bits()) == 0 {
Some(Self { bits })
} else {
None
}
}

/// Convert from underlying bit representation, dropping any bits
/// that do not correspond to flags.
#[inline]
pub const fn from_bits_truncate(bits: u32) -> Self {
Self {
bits: bits & Self::all().bits,
}
}

/// Returns `true` if no flags are currently stored.
#[inline]
pub const fn is_empty(&self) -> bool {
self.bits() == Self::empty().bits()
}

/// Returns `true` if there are flags common to both `self` and `other`.
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
!(Self {
bits: self.bits & other.bits,
})
.is_empty()
}

/// Returns `true` if all of the flags in `other` are contained within `self`.
#[inline]
pub const fn contains(&self, other: Self) -> bool {
(self.bits & other.bits) == other.bits
}

/// Inserts the specified flags in-place.
#[inline]
pub fn insert(&mut self, other: Self) {
self.bits |= other.bits;
}

/// Removes the specified flags in-place.
#[inline]
pub fn remove(&mut self, other: Self) {
self.bits &= !other.bits;
}

/// Toggles the specified flags in-place.
#[inline]
pub fn toggle(&mut self, other: Self) {
self.bits ^= other.bits;
}

/// Returns the intersection between the flags in `self` and
/// `other`.
///
/// Specifically, the returned set contains only the flags which are
/// present in *both* `self` *and* `other`.
///
/// This is equivalent to using the `&` operator (e.g.
/// [`ops::BitAnd`]), as in `flags & other`.
///
/// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self {
bits: self.bits & other.bits,
}
}

/// Returns the union of between the flags in `self` and `other`.
///
/// Specifically, the returned set contains all flags which are
/// present in *either* `self` *or* `other`, including any which are
/// present in both.
///
/// This is equivalent to using the `|` operator (e.g.
/// [`ops::BitOr`]), as in `flags | other`.
///
/// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self {
bits: self.bits | other.bits,
}
}

/// Returns the difference between the flags in `self` and `other`.
///
/// Specifically, the returned set contains all flags present in
/// `self`, except for the ones present in `other`.
///
/// It is also conceptually equivalent to the "bit-clear" operation:
/// `flags & !other` (and this syntax is also supported).
///
/// This is equivalent to using the `-` operator (e.g.
/// [`ops::Sub`]), as in `flags - other`.
///
/// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self {
bits: self.bits & !other.bits,
}
}
}

impl std::ops::BitOr for PaletteType {
type Output = Self;

/// Returns the union of the two sets of flags.
#[inline]
fn bitor(self, other: PaletteType) -> Self {
Self {
bits: self.bits | other.bits,
}
}
}

impl std::ops::BitOrAssign for PaletteType {
/// Adds the set of flags.
#[inline]
fn bitor_assign(&mut self, other: Self) {
self.bits |= other.bits;
}
}

impl std::ops::BitXor for PaletteType {
type Output = Self;

/// Returns the left flags, but with all the right flags toggled.
#[inline]
fn bitxor(self, other: Self) -> Self {
Self {
bits: self.bits ^ other.bits,
}
}
}

impl std::ops::BitXorAssign for PaletteType {
/// Toggles the set of flags.
#[inline]
fn bitxor_assign(&mut self, other: Self) {
self.bits ^= other.bits;
}
}

impl std::ops::BitAnd for PaletteType {
type Output = Self;

/// Returns the intersection between the two sets of flags.
#[inline]
fn bitand(self, other: Self) -> Self {
Self {
bits: self.bits & other.bits,
}
}
}

impl std::ops::BitAndAssign for PaletteType {
/// Disables all flags disabled in the set.
#[inline]
fn bitand_assign(&mut self, other: Self) {
self.bits &= other.bits;
}
}

impl std::ops::Sub for PaletteType {
type Output = Self;

/// Returns the set difference of the two sets of flags.
#[inline]
fn sub(self, other: Self) -> Self {
Self {
bits: self.bits & !other.bits,
}
}
}

impl std::ops::SubAssign for PaletteType {
/// Disables all flags enabled in the set.
#[inline]
fn sub_assign(&mut self, other: Self) {
self.bits &= !other.bits;
}
}

impl std::ops::Not for PaletteType {
type Output = Self;

/// Returns the complement of this set of flags.
#[inline]
fn not(self) -> Self {
Self { bits: !self.bits } & Self::all()
}
}

impl std::fmt::Debug for PaletteType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let members: &[(&str, Self)] = &[
(
"USABLE_WITH_LIGHT_BACKGROUND",
Self::USABLE_WITH_LIGHT_BACKGROUND,
),
(
"USABLE_WITH_DARK_BACKGROUND",
Self::USABLE_WITH_DARK_BACKGROUND,
),
];
let mut first = true;
for (name, value) in members {
if self.contains(*value) {
if !first {
f.write_str(" | ")?;
}
first = false;
f.write_str(name)?;
}
}
if first {
f.write_str("(empty)")?;
}
Ok(())
}
}

impl std::fmt::Binary for PaletteType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Binary::fmt(&self.bits, f)
}
}

impl std::fmt::Octal for PaletteType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Octal::fmt(&self.bits, f)
}
}

impl std::fmt::LowerHex for PaletteType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::LowerHex::fmt(&self.bits, f)
}
}

impl std::fmt::UpperHex for PaletteType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::UpperHex::fmt(&self.bits, f)
}
}

impl font_types::Scalar for PaletteType {
type Raw = <u32 as font_types::Scalar>::Raw;
fn to_raw(self) -> Self::Raw {
self.bits().to_raw()
}
fn from_raw(raw: Self::Raw) -> Self {
let t = <u32>::from_raw(raw);
Self::from_bits_truncate(t)
}
}

#[cfg(feature = "traversal")]
impl<'a> From<PaletteType> for FieldType<'a> {
fn from(src: PaletteType) -> FieldType<'a> {
src.bits().into()
}
}

/// [CPAL (Color Record)](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal#palette-entries-and-color-records) record
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
Expand Down
10 changes: 9 additions & 1 deletion resources/codegen_inputs/cpal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ table Cpal {
#[since_version(1)]
#[nullable]
#[read_offset_with($num_palettes)]
palette_types_array_offset: Offset32<[u32]>,
palette_types_array_offset: Offset32<[PaletteType]>,
/// Offset from the beginning of CPAL table to the [Palette Labels Array][].
///
/// This is an array of 'name' table IDs (typically in the font-specific name
Expand All @@ -58,6 +58,14 @@ table Cpal {
palette_entry_labels_array_offset: Offset32<[NameId]>,
}

/// The [PaletteType](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal#palette-type-array) flags.
flags u32 PaletteType {
/// Bit 0: palette is appropriate to use when displaying the font on a light background such as white.
USABLE_WITH_LIGHT_BACKGROUND = 0x0001,
/// Bit 1: palette is appropriate to use when displaying the font on a dark background such as black.
USABLE_WITH_DARK_BACKGROUND = 0x0002,
}

/// [CPAL (Color Record)](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal#palette-entries-and-color-records) record
record ColorRecord {
/// Blue value (B0).
Expand Down
10 changes: 9 additions & 1 deletion write-fonts/generated/generated_cpal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#[allow(unused_imports)]
use crate::codegen_prelude::*;

pub use read_fonts::tables::cpal::PaletteType;

/// [CPAL (Color Palette Table)](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal#palette-table-header) table
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand All @@ -26,7 +28,7 @@ pub struct Cpal {
/// This is an array of 32-bit flag fields that describe properties of each palette.
///
/// [Palette Types Array]: https://learn.microsoft.com/en-us/typography/opentype/spec/cpal#palette-type-array
pub palette_types_array: NullableOffsetMarker<Vec<u32>, WIDTH_32>,
pub palette_types_array: NullableOffsetMarker<Vec<PaletteType>, WIDTH_32>,
/// Offset from the beginning of CPAL table to the [Palette Labels Array][].
///
/// This is an array of 'name' table IDs (typically in the font-specific name
Expand Down Expand Up @@ -135,6 +137,12 @@ impl<'a> FontRead<'a> for Cpal {
}
}

impl FontWrite for PaletteType {
fn write_into(&self, writer: &mut TableWriter) {
writer.write_slice(&self.bits().to_be_bytes())
}
}

/// [CPAL (Color Record)](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal#palette-entries-and-color-records) record
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down