Skip to content

Commit 6957d0a

Browse files
authored
Remove Mix::Clip (#124)
Also re-orders the `bytemuck` tests to be in alphabetical order. See discussion in [#vello > Mix::Clip optimisation: Interaction with layers](https://xi.zulipchat.com/#narrow/channel/197075-vello/topic/Mix.3A.3AClip.20optimisation.3A.20Interaction.20with.20layers/with/537093339). This is of course still useful functionality, but it does not belong in `Peniko`; instead, renderers wishing to expose this optimisation should do so individually. This PR cannot be merged until a PR integrating this has been opened in Vello.
1 parent 639684a commit 6957d0a

File tree

6 files changed

+99
-51
lines changed

6 files changed

+99
-51
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ This release has an [MSRV] of 1.82.
2020
- Derive `Eq` and `Hash` on `InterpolationAlphaSpace`. ([#148][] by [@sagudev][])
2121
- There is now a `From` conversion from `&ImageData` to `ImageBrushRef`. ([#147][] by [@DJMcNab][])
2222

23+
### Removed
24+
25+
- Breaking change: `Mix::Clip` has been removed; it was previously deprecated in v0.5.0. ([#124][] by [@DJMcNab][])
26+
2327
## [0.5.0][] (2025-10-01)
2428

2529
This release has an [MSRV] of 1.82.
@@ -183,6 +187,7 @@ This release has an [MSRV] of 1.70.
183187
[#120]: https://github.com/linebender/peniko/pull/120
184188
[#121]: https://github.com/linebender/peniko/pull/121
185189
[#123]: https://github.com/linebender/peniko/pull/123
190+
[#124]: https://github.com/linebender/peniko/pull/124
186191
[#126]: https://github.com/linebender/peniko/pull/126
187192
[#127]: https://github.com/linebender/peniko/pull/127
188193
[#129]: https://github.com/linebender/peniko/pull/129

src/blend.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,7 @@ pub enum Mix {
8484
///
8585
/// ![](https://www.w3.org/TR/compositing-1/examples/luminosity.png)
8686
Luminosity = 15,
87-
/// `Clip` was similar to `Normal`, but was optimised for clipping (by avoiding
88-
/// blending in areas where there was no clip path).
89-
///
90-
/// This optimisation is however unrelated to mixing, and so will no longer
91-
/// be indicated with this enum.
92-
///
93-
/// If you were using this with Vello, you should use the (new) `push_clip_layer` function instead.
94-
#[deprecated(note = "Use `push_clip_layer` instead.", since = "0.5.0")]
95-
Clip = 128,
96-
// NOTICE: If a new value is added, be sure to update the bytemuck CheckedBitPattern impl.
87+
// NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl.
9788
}
9889

9990
/// Defines the layer composition function for a [blend operation](BlendMode).
@@ -159,7 +150,7 @@ pub enum Compose {
159150
/// Allows two elements to cross fade by changing their opacities from 0 to 1 on one
160151
/// element and 1 to 0 on the other element.
161152
PlusLighter = 13,
162-
// NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the bytemuck impl.
153+
// NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl.
163154
}
164155

165156
/// Blend mode consisting of [color mixing](Mix) and [composition functions](Compose).

src/brush.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,5 @@ pub enum Extend {
164164
Repeat = 1,
165165
/// Extends the image by reflecting the brush.
166166
Reflect = 2,
167+
// NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl.
167168
}

src/image.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub enum ImageFormat {
1313
Rgba8 = 0,
1414
/// 32-bit BGRA with 8-bit channels.
1515
Bgra8 = 1,
16-
// NOTICE: If a new value is added, be sure to update the bytemuck CheckedBitPattern impl.
16+
// NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl.
1717
}
1818

1919
impl ImageFormat {
@@ -40,6 +40,7 @@ pub enum ImageAlphaType {
4040
Alpha = 0,
4141
/// Image has colors with premultiplied alpha.
4242
AlphaPremultiplied = 1,
43+
// NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl.
4344
}
4445

4546
/// Defines the desired quality for sampling an image.
@@ -60,7 +61,7 @@ pub enum ImageQuality {
6061
///
6162
/// This is typically bicubic sampling.
6263
High = 2,
63-
// NOTICE: If a new value is added, be sure to update the bytemuck CheckedBitPattern impl.
64+
// NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl.
6465
}
6566

6667
/// Owned shareable image resource.

src/impl_bytemuck.rs

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,13 @@ unsafe impl bytemuck::Contiguous for Fill {
8181
}
8282

8383
// Safety: The enum is `repr(u8)` and has only fieldless variants.
84-
unsafe impl bytemuck::NoUninit for ImageFormat {}
84+
unsafe impl bytemuck::NoUninit for ImageAlphaType {}
8585

8686
// Safety: The enum is `repr(u8)` and `0` is a valid value.
87-
unsafe impl bytemuck::Zeroable for ImageFormat {}
87+
unsafe impl bytemuck::Zeroable for ImageAlphaType {}
8888

8989
// Safety: The enum is `repr(u8)`.
90-
unsafe impl bytemuck::checked::CheckedBitPattern for ImageFormat {
90+
unsafe impl bytemuck::checked::CheckedBitPattern for ImageAlphaType {
9191
type Bits = u8;
9292

9393
fn is_valid_bit_pattern(bits: &u8) -> bool {
@@ -99,20 +99,20 @@ unsafe impl bytemuck::checked::CheckedBitPattern for ImageFormat {
9999

100100
// Safety: The enum is `repr(u8)`. All values are `u8` and fall within
101101
// the min and max values.
102-
unsafe impl bytemuck::Contiguous for ImageFormat {
102+
unsafe impl bytemuck::Contiguous for ImageAlphaType {
103103
type Int = u8;
104-
const MIN_VALUE: u8 = Self::Rgba8 as u8;
105-
const MAX_VALUE: u8 = Self::Bgra8 as u8;
104+
const MIN_VALUE: u8 = Self::Alpha as u8;
105+
const MAX_VALUE: u8 = Self::AlphaPremultiplied as u8;
106106
}
107107

108108
// Safety: The enum is `repr(u8)` and has only fieldless variants.
109-
unsafe impl bytemuck::NoUninit for ImageAlphaType {}
109+
unsafe impl bytemuck::NoUninit for ImageFormat {}
110110

111111
// Safety: The enum is `repr(u8)` and `0` is a valid value.
112-
unsafe impl bytemuck::Zeroable for ImageAlphaType {}
112+
unsafe impl bytemuck::Zeroable for ImageFormat {}
113113

114114
// Safety: The enum is `repr(u8)`.
115-
unsafe impl bytemuck::checked::CheckedBitPattern for ImageAlphaType {
115+
unsafe impl bytemuck::checked::CheckedBitPattern for ImageFormat {
116116
type Bits = u8;
117117

118118
fn is_valid_bit_pattern(bits: &u8) -> bool {
@@ -124,10 +124,10 @@ unsafe impl bytemuck::checked::CheckedBitPattern for ImageAlphaType {
124124

125125
// Safety: The enum is `repr(u8)`. All values are `u8` and fall within
126126
// the min and max values.
127-
unsafe impl bytemuck::Contiguous for ImageAlphaType {
127+
unsafe impl bytemuck::Contiguous for ImageFormat {
128128
type Int = u8;
129-
const MIN_VALUE: u8 = Self::Alpha as u8;
130-
const MAX_VALUE: u8 = Self::AlphaPremultiplied as u8;
129+
const MIN_VALUE: u8 = Self::Rgba8 as u8;
130+
const MAX_VALUE: u8 = Self::Bgra8 as u8;
131131
}
132132

133133
// Safety: The enum is `repr(u8)` and has only fieldless variants.
@@ -165,12 +165,21 @@ unsafe impl bytemuck::Zeroable for Mix {}
165165
unsafe impl bytemuck::checked::CheckedBitPattern for Mix {
166166
type Bits = u8;
167167

168-
#[expect(deprecated, reason = "Mix::Clip is still a valid bit pattern for now.")]
169168
fn is_valid_bit_pattern(bits: &u8) -> bool {
170-
*bits <= Self::Luminosity as u8 || *bits == Self::Clip as u8
169+
use bytemuck::Contiguous;
170+
// Don't need to compare against MIN_VALUE as this is u8 and 0 is the MIN_VALUE.
171+
*bits <= Self::MAX_VALUE
171172
}
172173
}
173174

175+
// Safety: The enum is `repr(u8)`. All values are `u8` and fall within
176+
// the min and max values.
177+
unsafe impl bytemuck::Contiguous for Mix {
178+
type Int = u8;
179+
const MIN_VALUE: u8 = Self::Normal as u8;
180+
const MAX_VALUE: u8 = Self::Luminosity as u8;
181+
}
182+
174183
#[cfg(test)]
175184
mod tests {
176185
use crate::{Compose, Extend, Fill, ImageAlphaType, ImageFormat, ImageQuality, Mix};
@@ -200,7 +209,7 @@ mod tests {
200209
Ok(&ImageAlphaType::AlphaPremultiplied),
201210
try_from_bytes::<ImageAlphaType>(valid_one)
202211
);
203-
assert!(try_from_bytes::<ImageFormat>(invalid).is_err());
212+
assert!(try_from_bytes::<ImageAlphaType>(invalid).is_err());
204213

205214
assert_eq!(
206215
Ok(&ImageFormat::Rgba8),
@@ -242,20 +251,29 @@ mod tests {
242251

243252
assert_eq!(None, Fill::from_integer(255));
244253

245-
let image_format_1 = ImageFormat::Rgba8;
246-
let image_format_2 = ImageFormat::from_integer(image_format_1.into_integer());
247-
assert_eq!(Some(image_format_1), image_format_2);
248-
249254
let image_alpha_type_1 = ImageAlphaType::Alpha;
250255
let image_alpha_type_2 = ImageAlphaType::from_integer(image_alpha_type_1.into_integer());
251256
assert_eq!(Some(image_alpha_type_1), image_alpha_type_2);
257+
252258
assert_eq!(None, ImageAlphaType::from_integer(255));
253259

260+
let image_format_1 = ImageFormat::Rgba8;
261+
let image_format_2 = ImageFormat::from_integer(image_format_1.into_integer());
262+
assert_eq!(Some(image_format_1), image_format_2);
263+
264+
assert_eq!(None, ImageFormat::from_integer(255));
265+
254266
let image_quality_1 = ImageQuality::Low;
255267
let image_quality_2 = ImageQuality::from_integer(image_quality_1.into_integer());
256268
assert_eq!(Some(image_quality_1), image_quality_2);
257269

258270
assert_eq!(None, ImageQuality::from_integer(255));
271+
272+
let mix_1 = Mix::Multiply;
273+
let mix_2 = Mix::from_integer(mix_1.into_integer());
274+
assert_eq!(Some(mix_1), mix_2);
275+
276+
assert_eq!(None, Mix::from_integer(255));
259277
}
260278

261279
#[test]
@@ -269,12 +287,12 @@ mod tests {
269287
let fill = Fill::zeroed();
270288
assert_eq!(fill, Fill::NonZero);
271289

272-
let image_format = ImageFormat::zeroed();
273-
assert_eq!(image_format, ImageFormat::Rgba8);
274-
275290
let image_alpha_type = ImageAlphaType::zeroed();
276291
assert_eq!(image_alpha_type, ImageAlphaType::Alpha);
277292

293+
let image_format = ImageFormat::zeroed();
294+
assert_eq!(image_format, ImageFormat::Rgba8);
295+
278296
let image_quality = ImageQuality::zeroed();
279297
assert_eq!(image_quality, ImageQuality::Low);
280298

@@ -324,6 +342,20 @@ mod tests {
324342
}
325343
};
326344

345+
/// Tests that the [`Contiguous`] impl for [`ImageAlphaType`] is not trivially incorrect.
346+
const _: () = {
347+
let mut value = 0;
348+
while value <= ImageAlphaType::MAX_VALUE {
349+
// Safety: In a const context, therefore if this makes an invalid ImageFormat, that will be detected.
350+
let it: ImageAlphaType = unsafe { ptr::read((&raw const value).cast()) };
351+
// Evaluate the enum value to ensure it actually has a valid tag
352+
if it as u8 != value {
353+
unreachable!();
354+
}
355+
value += 1;
356+
}
357+
};
358+
327359
/// Tests that the [`Contiguous`] impl for [`ImageFormat`] is not trivially incorrect.
328360
const _: () = {
329361
let mut value = 0;
@@ -338,12 +370,12 @@ mod tests {
338370
}
339371
};
340372

341-
/// Tests that the [`Contiguous`] impl for [`ImageAlphaType`] is not trivially incorrect.
373+
/// Tests that the [`Contiguous`] impl for [`ImageQuality`] is not trivially incorrect.
342374
const _: () = {
343375
let mut value = 0;
344-
while value <= ImageAlphaType::MAX_VALUE {
345-
// Safety: In a const context, therefore if this makes an invalid ImageFormat, that will be detected.
346-
let it: ImageAlphaType = unsafe { ptr::read((&raw const value).cast()) };
376+
while value <= ImageQuality::MAX_VALUE {
377+
// Safety: In a const context, therefore if this makes an invalid ImageQuality, that will be detected.
378+
let it: ImageQuality = unsafe { ptr::read((&raw const value).cast()) };
347379
// Evaluate the enum value to ensure it actually has a valid tag
348380
if it as u8 != value {
349381
unreachable!();
@@ -352,7 +384,7 @@ mod tests {
352384
}
353385
};
354386

355-
/// Tests that the [`Contiguous`] impl for [`ImageQuality`] is not trivially incorrect.
387+
/// Tests that the [`Contiguous`] impl for [`Mix`] is not trivially incorrect.
356388
const _: () = {
357389
let mut value = 0;
358390
while value <= ImageQuality::MAX_VALUE {
@@ -426,41 +458,41 @@ mod doctests {
426458
/// ```
427459
const _FILL: () = {};
428460

429-
/// Validates that any new variants in `ImageFormat` has led to a change in the `Contiguous` impl.
461+
/// Validates that any new variants in `ImageAlphaType` has led to a change in the `Contiguous` impl.
430462
/// Note that to test this robustly, we'd need 256 tests, which is impractical.
431463
/// We make the assumption that all new variants will maintain contiguousness.
432464
///
433465
/// ```compile_fail,E0080
434466
/// use bytemuck::Contiguous;
435-
/// use peniko::ImageFormat;
467+
/// use peniko::ImageAlphaType;
436468
/// const {
437-
/// let value = ImageFormat::MAX_VALUE + 1;
438-
/// let it: ImageFormat = unsafe { core::ptr::read((&raw const value).cast()) };
469+
/// let value = ImageAlphaType::MAX_VALUE + 1;
470+
/// let it: ImageAlphaType = unsafe { core::ptr::read((&raw const value).cast()) };
439471
/// // Evaluate the enum value to ensure it actually has an invalid tag
440472
/// if it as u8 != value {
441473
/// unreachable!();
442474
/// }
443475
/// }
444476
/// ```
445-
const _IMAGE_FORMAT: () = {};
477+
const _IMAGE_ALPHA_TYPE: () = {};
446478

447-
/// Validates that any new variants in `ImageAlphaType` has led to a change in the `Contiguous` impl.
479+
/// Validates that any new variants in `ImageFormat` has led to a change in the `Contiguous` impl.
448480
/// Note that to test this robustly, we'd need 256 tests, which is impractical.
449481
/// We make the assumption that all new variants will maintain contiguousness.
450482
///
451483
/// ```compile_fail,E0080
452484
/// use bytemuck::Contiguous;
453-
/// use peniko::ImageAlphaType;
485+
/// use peniko::ImageFormat;
454486
/// const {
455-
/// let value = ImageAlphaType::MAX_VALUE + 1;
456-
/// let it: ImageAlphaType = unsafe { core::ptr::read((&raw const value).cast()) };
487+
/// let value = ImageFormat::MAX_VALUE + 1;
488+
/// let it: ImageFormat = unsafe { core::ptr::read((&raw const value).cast()) };
457489
/// // Evaluate the enum value to ensure it actually has an invalid tag
458490
/// if it as u8 != value {
459491
/// unreachable!();
460492
/// }
461493
/// }
462494
/// ```
463-
const _IMAGE_ALPHA_TYPE: () = {};
495+
const _IMAGE_FORMAT: () = {};
464496

465497
/// Validates that any new variants in `ImageQuality` has led to a change in the `Contiguous` impl.
466498
/// Note that to test this robustly, we'd need 256 tests, which is impractical.
@@ -479,4 +511,22 @@ mod doctests {
479511
/// }
480512
/// ```
481513
const _IMAGE_QUALITY: () = {};
514+
515+
/// Validates that any new variants in `Mix` has led to a change in the `Contiguous` impl.
516+
/// Note that to test this robustly, we'd need 256 tests, which is impractical.
517+
/// We make the assumption that all new variants will maintain contiguousness.
518+
///
519+
/// ```compile_fail,E0080
520+
/// use bytemuck::Contiguous;
521+
/// use peniko::Mix;
522+
/// const {
523+
/// let value = Mix::MAX_VALUE + 1;
524+
/// let it: Mix = unsafe { core::ptr::read((&raw const value).cast()) };
525+
/// // Evaluate the enum value to ensure it actually has an invalid tag
526+
/// if it as u8 != value {
527+
/// unreachable!();
528+
/// }
529+
/// }
530+
/// ```
531+
const _MIX: () = {};
482532
}

src/style.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub enum Fill {
2727
/// number state can be stored in only one bit (and so the winding numbers for
2828
/// several pixels can be packed extremely efficiently).
2929
EvenOdd = 1,
30-
// NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the bytemuck impl.
30+
// NOTICE: If a new value is added, be sure to modify `MAX_VALUE` in the `bytemuck::Contiguous` impl.
3131
}
3232

3333
/// Describes draw style-- either a [fill](Fill) or [stroke](Stroke).

0 commit comments

Comments
 (0)