diff --git a/piet-gpu/src/samples.rs b/piet-gpu/src/samples.rs index 8cb0392..bcde384 100644 --- a/piet-gpu/src/samples.rs +++ b/piet-gpu/src/samples.rs @@ -226,7 +226,7 @@ pub fn render_blend_grid(sb: &mut SceneBuilder) { fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affine) { // Inspired by https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode let rect = Rect::from_origin_size(Point::new(0., 0.), (200., 200.)); - let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::BLACK, Color::WHITE]); + let linear = LinearGradient::new((0.0, 0.0), (200.0, 0.0)).stops([Color::BLACK, Color::WHITE]); sb.fill(Fill::NonZero, transform, &linear.into(), None, &rect); const GRADIENTS: &[(f64, f64, Color)] = &[ (150., 0., Color::rgb8(255, 240, 64)), @@ -236,7 +236,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin for (x, y, c) in GRADIENTS { let mut color2 = c.clone(); color2.a = 0; - let radial = RadialGradient::new((*x, *y), 100.0).stops([c.clone(), color2]); + let radial = RadialGradient::new((*x, *y), 100.0).stops([*c, color2]); sb.fill(Fill::NonZero, transform, &radial.into(), None, &rect); } const COLORS: &[Color] = &[ @@ -246,17 +246,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin ]; sb.push_layer(Mix::Normal.into(), transform, &rect); for (i, c) in COLORS.iter().enumerate() { - // let stops = &[ - // GradientStop { - // color: Color::rgb8(255, 255, 255), - // offset: 0.0, - // }, - // GradientStop { - // color: c.clone(), - // offset: 1.0, - // }, - // ][..]; - let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::WHITE, c.clone()]); + let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::WHITE, *c]); sb.push_layer(blend, transform, &rect); // squash the ellipse let a = transform diff --git a/piet-scene/src/scene/builder.rs b/piet-scene/src/scene/builder.rs index 767962e..65ff186 100644 --- a/piet-scene/src/scene/builder.rs +++ b/piet-scene/src/scene/builder.rs @@ -24,7 +24,7 @@ use smallvec::SmallVec; /// Builder for constructing a scene or scene fragment. pub struct SceneBuilder<'a> { scene: &'a mut SceneData, - layers: SmallVec<[BlendMode; 8]>, + layers: SmallVec<[(BlendMode, bool); 8]>, } impl<'a> SceneBuilder<'a> { @@ -54,15 +54,23 @@ impl<'a> SceneBuilder<'a> { pub fn push_layer(&mut self, blend: BlendMode, transform: Affine, shape: &impl Shape) { self.maybe_encode_transform(transform); self.linewidth(-1.0); - self.encode_path(shape, true); - self.begin_clip(blend); - self.layers.push(blend); + if self.encode_path(shape, true) { + self.begin_clip(blend); + self.layers.push((blend, true)); + } else { + // When the layer has an empty path, record an entry to prevent + // the stack from becoming unbalanced. This is handled in + // pop_layer. + self.layers.push((blend, false)); + } } /// Pops the current layer. pub fn pop_layer(&mut self) { - if let Some(layer) = self.layers.pop() { - self.end_clip(layer); + if let Some((blend, active)) = self.layers.pop() { + if active { + self.end_clip(blend); + } } } @@ -117,8 +125,8 @@ impl<'a> SceneBuilder<'a> { /// Completes construction and finalizes the underlying scene. pub fn finish(mut self) { - while let Some(layer) = self.layers.pop() { - self.end_clip(layer); + while !self.layers.is_empty() { + self.pop_layer(); } } } diff --git a/piet-wgsl/src/test_scene.rs b/piet-wgsl/src/test_scene.rs index 899d05c..bb4c4ae 100644 --- a/piet-wgsl/src/test_scene.rs +++ b/piet-wgsl/src/test_scene.rs @@ -133,7 +133,7 @@ pub fn render_blend_grid(sb: &mut SceneBuilder) { fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affine) { // Inspired by https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode let rect = Rect::from_origin_size(Point::new(0., 0.), (200., 200.)); - let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::BLACK, Color::WHITE]); + let linear = LinearGradient::new((0.0, 0.0), (200.0, 0.0)).stops([Color::BLACK, Color::WHITE]); sb.fill(Fill::NonZero, transform, &linear.into(), None, &rect); const GRADIENTS: &[(f64, f64, Color)] = &[ (150., 0., Color::rgb8(255, 240, 64)), @@ -143,7 +143,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin for (x, y, c) in GRADIENTS { let mut color2 = c.clone(); color2.a = 0; - let radial = RadialGradient::new((*x, *y), 100.0).stops([c.clone(), color2]); + let radial = RadialGradient::new((*x, *y), 100.0).stops([*c, color2]); sb.fill(Fill::NonZero, transform, &radial.into(), None, &rect); } const COLORS: &[Color] = &[ @@ -153,17 +153,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin ]; sb.push_layer(Mix::Normal.into(), transform, &rect); for (i, c) in COLORS.iter().enumerate() { - // let stops = &[ - // GradientStop { - // color: Color::rgb8(255, 255, 255), - // offset: 0.0, - // }, - // GradientStop { - // color: c.clone(), - // offset: 1.0, - // }, - // ][..]; - let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::WHITE, c.clone()]); + let linear = LinearGradient::new((0.0, 0.0), (0.0, 200.0)).stops([Color::WHITE, *c]); sb.push_layer(blend, transform, &rect); // squash the ellipse let a = transform