diff --git a/CHANGELOG.md b/CHANGELOG.md index 4072228..0bd9c54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ This release has an [MSRV] of 1.82. - Derive `Eq` and `Hash` on `InterpolationAlphaSpace`. ([#148][] by [@sagudev][]) +### Removed + +- Breaking change: `Mix::Clip` has been removed; it was previously deprecated in v0.5.0. ([#124][] by [@DJMcNab][]) + ## [0.5.0][] (2025-10-01) This release has an [MSRV] of 1.82. @@ -182,6 +186,7 @@ This release has an [MSRV] of 1.70. [#120]: https://github.com/linebender/peniko/pull/120 [#121]: https://github.com/linebender/peniko/pull/121 [#123]: https://github.com/linebender/peniko/pull/123 +[#124]: https://github.com/linebender/peniko/pull/124 [#126]: https://github.com/linebender/peniko/pull/126 [#127]: https://github.com/linebender/peniko/pull/127 [#129]: https://github.com/linebender/peniko/pull/129 diff --git a/src/blend.rs b/src/blend.rs index 546b3a6..d45e0c9 100644 --- a/src/blend.rs +++ b/src/blend.rs @@ -84,16 +84,7 @@ pub enum Mix { /// /// ![](https://www.w3.org/TR/compositing-1/examples/luminosity.png) Luminosity = 15, - /// `Clip` was similar to `Normal`, but was optimised for clipping (by avoiding - /// blending in areas where there was no clip path). - /// - /// This optimisation is however unrelated to mixing, and so will no longer - /// be indicated with this enum. - /// - /// If you were using this with Vello, you should use the (new) `push_clip_layer` function instead. - #[deprecated(note = "Use `push_clip_layer` instead.", since = "0.5.0")] - Clip = 128, - // NOTICE: If a new value is added, be sure to update the bytemuck CheckedBitPattern impl. + // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl. } /// Defines the layer composition function for a [blend operation](BlendMode). @@ -159,7 +150,7 @@ pub enum Compose { /// Allows two elements to cross fade by changing their opacities from 0 to 1 on one /// element and 1 to 0 on the other element. PlusLighter = 13, - // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the bytemuck impl. + // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl. } /// Blend mode consisting of [color mixing](Mix) and [composition functions](Compose). diff --git a/src/brush.rs b/src/brush.rs index 0e3b00b..a1eb2c3 100644 --- a/src/brush.rs +++ b/src/brush.rs @@ -164,4 +164,5 @@ pub enum Extend { Repeat = 1, /// Extends the image by reflecting the brush. Reflect = 2, + // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl. } diff --git a/src/image.rs b/src/image.rs index 1d5b294..964edff 100644 --- a/src/image.rs +++ b/src/image.rs @@ -13,7 +13,7 @@ pub enum ImageFormat { Rgba8 = 0, /// 32-bit BGRA with 8-bit channels. Bgra8 = 1, - // NOTICE: If a new value is added, be sure to update the bytemuck CheckedBitPattern impl. + // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl. } impl ImageFormat { @@ -40,6 +40,7 @@ pub enum ImageAlphaType { Alpha = 0, /// Image has colors with premultiplied alpha. AlphaPremultiplied = 1, + // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl. } /// Defines the desired quality for sampling an image. @@ -60,7 +61,7 @@ pub enum ImageQuality { /// /// This is typically bicubic sampling. High = 2, - // NOTICE: If a new value is added, be sure to update the bytemuck CheckedBitPattern impl. + // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl. } /// Owned shareable image resource. diff --git a/src/impl_bytemuck.rs b/src/impl_bytemuck.rs index b5c10bb..9e54645 100644 --- a/src/impl_bytemuck.rs +++ b/src/impl_bytemuck.rs @@ -81,13 +81,13 @@ unsafe impl bytemuck::Contiguous for Fill { } // Safety: The enum is `repr(u8)` and has only fieldless variants. -unsafe impl bytemuck::NoUninit for ImageFormat {} +unsafe impl bytemuck::NoUninit for ImageAlphaType {} // Safety: The enum is `repr(u8)` and `0` is a valid value. -unsafe impl bytemuck::Zeroable for ImageFormat {} +unsafe impl bytemuck::Zeroable for ImageAlphaType {} // Safety: The enum is `repr(u8)`. -unsafe impl bytemuck::checked::CheckedBitPattern for ImageFormat { +unsafe impl bytemuck::checked::CheckedBitPattern for ImageAlphaType { type Bits = u8; fn is_valid_bit_pattern(bits: &u8) -> bool { @@ -99,20 +99,20 @@ unsafe impl bytemuck::checked::CheckedBitPattern for ImageFormat { // Safety: The enum is `repr(u8)`. All values are `u8` and fall within // the min and max values. -unsafe impl bytemuck::Contiguous for ImageFormat { +unsafe impl bytemuck::Contiguous for ImageAlphaType { type Int = u8; - const MIN_VALUE: u8 = Self::Rgba8 as u8; - const MAX_VALUE: u8 = Self::Bgra8 as u8; + const MIN_VALUE: u8 = Self::Alpha as u8; + const MAX_VALUE: u8 = Self::AlphaPremultiplied as u8; } // Safety: The enum is `repr(u8)` and has only fieldless variants. -unsafe impl bytemuck::NoUninit for ImageAlphaType {} +unsafe impl bytemuck::NoUninit for ImageFormat {} // Safety: The enum is `repr(u8)` and `0` is a valid value. -unsafe impl bytemuck::Zeroable for ImageAlphaType {} +unsafe impl bytemuck::Zeroable for ImageFormat {} // Safety: The enum is `repr(u8)`. -unsafe impl bytemuck::checked::CheckedBitPattern for ImageAlphaType { +unsafe impl bytemuck::checked::CheckedBitPattern for ImageFormat { type Bits = u8; fn is_valid_bit_pattern(bits: &u8) -> bool { @@ -124,10 +124,10 @@ unsafe impl bytemuck::checked::CheckedBitPattern for ImageAlphaType { // Safety: The enum is `repr(u8)`. All values are `u8` and fall within // the min and max values. -unsafe impl bytemuck::Contiguous for ImageAlphaType { +unsafe impl bytemuck::Contiguous for ImageFormat { type Int = u8; - const MIN_VALUE: u8 = Self::Alpha as u8; - const MAX_VALUE: u8 = Self::AlphaPremultiplied as u8; + const MIN_VALUE: u8 = Self::Rgba8 as u8; + const MAX_VALUE: u8 = Self::Bgra8 as u8; } // Safety: The enum is `repr(u8)` and has only fieldless variants. @@ -165,12 +165,21 @@ unsafe impl bytemuck::Zeroable for Mix {} unsafe impl bytemuck::checked::CheckedBitPattern for Mix { type Bits = u8; - #[expect(deprecated, reason = "Mix::Clip is still a valid bit pattern for now.")] fn is_valid_bit_pattern(bits: &u8) -> bool { - *bits <= Self::Luminosity as u8 || *bits == Self::Clip as u8 + use bytemuck::Contiguous; + // Don't need to compare against MIN_VALUE as this is u8 and 0 is the MIN_VALUE. + *bits <= Self::MAX_VALUE } } +// Safety: The enum is `repr(u8)`. All values are `u8` and fall within +// the min and max values. +unsafe impl bytemuck::Contiguous for Mix { + type Int = u8; + const MIN_VALUE: u8 = Self::Normal as u8; + const MAX_VALUE: u8 = Self::Luminosity as u8; +} + #[cfg(test)] mod tests { use crate::{Compose, Extend, Fill, ImageAlphaType, ImageFormat, ImageQuality, Mix}; @@ -200,7 +209,7 @@ mod tests { Ok(&ImageAlphaType::AlphaPremultiplied), try_from_bytes::(valid_one) ); - assert!(try_from_bytes::(invalid).is_err()); + assert!(try_from_bytes::(invalid).is_err()); assert_eq!( Ok(&ImageFormat::Rgba8), @@ -242,20 +251,29 @@ mod tests { assert_eq!(None, Fill::from_integer(255)); - let image_format_1 = ImageFormat::Rgba8; - let image_format_2 = ImageFormat::from_integer(image_format_1.into_integer()); - assert_eq!(Some(image_format_1), image_format_2); - let image_alpha_type_1 = ImageAlphaType::Alpha; let image_alpha_type_2 = ImageAlphaType::from_integer(image_alpha_type_1.into_integer()); assert_eq!(Some(image_alpha_type_1), image_alpha_type_2); + assert_eq!(None, ImageAlphaType::from_integer(255)); + let image_format_1 = ImageFormat::Rgba8; + let image_format_2 = ImageFormat::from_integer(image_format_1.into_integer()); + assert_eq!(Some(image_format_1), image_format_2); + + assert_eq!(None, ImageFormat::from_integer(255)); + let image_quality_1 = ImageQuality::Low; let image_quality_2 = ImageQuality::from_integer(image_quality_1.into_integer()); assert_eq!(Some(image_quality_1), image_quality_2); assert_eq!(None, ImageQuality::from_integer(255)); + + let mix_1 = Mix::Multiply; + let mix_2 = Mix::from_integer(mix_1.into_integer()); + assert_eq!(Some(mix_1), mix_2); + + assert_eq!(None, Mix::from_integer(255)); } #[test] @@ -269,12 +287,12 @@ mod tests { let fill = Fill::zeroed(); assert_eq!(fill, Fill::NonZero); - let image_format = ImageFormat::zeroed(); - assert_eq!(image_format, ImageFormat::Rgba8); - let image_alpha_type = ImageAlphaType::zeroed(); assert_eq!(image_alpha_type, ImageAlphaType::Alpha); + let image_format = ImageFormat::zeroed(); + assert_eq!(image_format, ImageFormat::Rgba8); + let image_quality = ImageQuality::zeroed(); assert_eq!(image_quality, ImageQuality::Low); @@ -324,6 +342,20 @@ mod tests { } }; + /// Tests that the [`Contiguous`] impl for [`ImageAlphaType`] is not trivially incorrect. + const _: () = { + let mut value = 0; + while value <= ImageAlphaType::MAX_VALUE { + // Safety: In a const context, therefore if this makes an invalid ImageFormat, that will be detected. + let it: ImageAlphaType = unsafe { ptr::read((&raw const value).cast()) }; + // Evaluate the enum value to ensure it actually has a valid tag + if it as u8 != value { + unreachable!(); + } + value += 1; + } + }; + /// Tests that the [`Contiguous`] impl for [`ImageFormat`] is not trivially incorrect. const _: () = { let mut value = 0; @@ -338,12 +370,12 @@ mod tests { } }; - /// Tests that the [`Contiguous`] impl for [`ImageAlphaType`] is not trivially incorrect. + /// Tests that the [`Contiguous`] impl for [`ImageQuality`] is not trivially incorrect. const _: () = { let mut value = 0; - while value <= ImageAlphaType::MAX_VALUE { - // Safety: In a const context, therefore if this makes an invalid ImageFormat, that will be detected. - let it: ImageAlphaType = unsafe { ptr::read((&raw const value).cast()) }; + while value <= ImageQuality::MAX_VALUE { + // Safety: In a const context, therefore if this makes an invalid ImageQuality, that will be detected. + let it: ImageQuality = unsafe { ptr::read((&raw const value).cast()) }; // Evaluate the enum value to ensure it actually has a valid tag if it as u8 != value { unreachable!(); @@ -352,7 +384,7 @@ mod tests { } }; - /// Tests that the [`Contiguous`] impl for [`ImageQuality`] is not trivially incorrect. + /// Tests that the [`Contiguous`] impl for [`Mix`] is not trivially incorrect. const _: () = { let mut value = 0; while value <= ImageQuality::MAX_VALUE { @@ -426,41 +458,41 @@ mod doctests { /// ``` const _FILL: () = {}; - /// Validates that any new variants in `ImageFormat` has led to a change in the `Contiguous` impl. + /// Validates that any new variants in `ImageAlphaType` has led to a change in the `Contiguous` impl. /// Note that to test this robustly, we'd need 256 tests, which is impractical. /// We make the assumption that all new variants will maintain contiguousness. /// /// ```compile_fail,E0080 /// use bytemuck::Contiguous; - /// use peniko::ImageFormat; + /// use peniko::ImageAlphaType; /// const { - /// let value = ImageFormat::MAX_VALUE + 1; - /// let it: ImageFormat = unsafe { core::ptr::read((&raw const value).cast()) }; + /// let value = ImageAlphaType::MAX_VALUE + 1; + /// let it: ImageAlphaType = unsafe { core::ptr::read((&raw const value).cast()) }; /// // Evaluate the enum value to ensure it actually has an invalid tag /// if it as u8 != value { /// unreachable!(); /// } /// } /// ``` - const _IMAGE_FORMAT: () = {}; + const _IMAGE_ALPHA_TYPE: () = {}; - /// Validates that any new variants in `ImageAlphaType` has led to a change in the `Contiguous` impl. + /// Validates that any new variants in `ImageFormat` has led to a change in the `Contiguous` impl. /// Note that to test this robustly, we'd need 256 tests, which is impractical. /// We make the assumption that all new variants will maintain contiguousness. /// /// ```compile_fail,E0080 /// use bytemuck::Contiguous; - /// use peniko::ImageAlphaType; + /// use peniko::ImageFormat; /// const { - /// let value = ImageAlphaType::MAX_VALUE + 1; - /// let it: ImageAlphaType = unsafe { core::ptr::read((&raw const value).cast()) }; + /// let value = ImageFormat::MAX_VALUE + 1; + /// let it: ImageFormat = unsafe { core::ptr::read((&raw const value).cast()) }; /// // Evaluate the enum value to ensure it actually has an invalid tag /// if it as u8 != value { /// unreachable!(); /// } /// } /// ``` - const _IMAGE_ALPHA_TYPE: () = {}; + const _IMAGE_FORMAT: () = {}; /// Validates that any new variants in `ImageQuality` has led to a change in the `Contiguous` impl. /// Note that to test this robustly, we'd need 256 tests, which is impractical. @@ -479,4 +511,22 @@ mod doctests { /// } /// ``` const _IMAGE_QUALITY: () = {}; + + /// Validates that any new variants in `Mix` has led to a change in the `Contiguous` impl. + /// Note that to test this robustly, we'd need 256 tests, which is impractical. + /// We make the assumption that all new variants will maintain contiguousness. + /// + /// ```compile_fail,E0080 + /// use bytemuck::Contiguous; + /// use peniko::Mix; + /// const { + /// let value = Mix::MAX_VALUE + 1; + /// let it: Mix = unsafe { core::ptr::read((&raw const value).cast()) }; + /// // Evaluate the enum value to ensure it actually has an invalid tag + /// if it as u8 != value { + /// unreachable!(); + /// } + /// } + /// ``` + const _MIX: () = {}; } diff --git a/src/style.rs b/src/style.rs index dda70e4..7e38259 100644 --- a/src/style.rs +++ b/src/style.rs @@ -27,7 +27,7 @@ pub enum Fill { /// number state can be stored in only one bit (and so the winding numbers for /// several pixels can be packed extremely efficiently). EvenOdd = 1, - // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the bytemuck impl. + // NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl. } /// Describes draw style-- either a [fill](Fill) or [stroke](Stroke).