address review feedback

This commit is contained in:
Chad Brokaw 2022-11-23 16:51:30 -05:00
parent fc1a6e9e4e
commit eccce74c4b
2 changed files with 35 additions and 25 deletions

View file

@ -1,5 +1,5 @@
use crate::PicoSvg; use crate::PicoSvg;
use piet_scene::kurbo::{Affine, Ellipse, PathEl, Point, Rect}; use piet_scene::kurbo::{Affine, BezPath, Ellipse, PathEl, Point, Rect};
use piet_scene::*; use piet_scene::*;
use crate::SimpleText; use crate::SimpleText;
@ -104,7 +104,7 @@ fn render_cardioid(sb: &mut SceneBuilder) {
let dth = std::f64::consts::PI * 2.0 / (n as f64); let dth = std::f64::consts::PI * 2.0 / (n as f64);
let center = Point::new(1024.0, 768.0); let center = Point::new(1024.0, 768.0);
let r = 750.0; let r = 750.0;
let mut path = vec![]; let mut path = BezPath::new();
for i in 1..n { for i in 1..n {
let mut p0 = center; let mut p0 = center;
let a0 = i as f64 * dth; let a0 = i as f64 * dth;
@ -122,7 +122,7 @@ fn render_cardioid(sb: &mut SceneBuilder) {
Affine::IDENTITY, Affine::IDENTITY,
Color::rgb8(0, 0, 0), Color::rgb8(0, 0, 0),
None, None,
&&path[..], &path,
); );
} }
@ -169,26 +169,22 @@ fn render_alpha_test(sb: &mut SceneBuilder) {
Affine::IDENTITY, Affine::IDENTITY,
Color::rgb8(255, 0, 0), Color::rgb8(255, 0, 0),
None, None,
&&make_diamond(1024.0, 100.0)[..], &make_diamond(1024.0, 100.0),
); );
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::IDENTITY, Affine::IDENTITY,
Color::rgba8(0, 255, 0, 0x80), Color::rgba8(0, 255, 0, 0x80),
None, None,
&&make_diamond(1024.0, 125.0)[..], &make_diamond(1024.0, 125.0),
);
sb.push_layer(
Mix::Clip,
Affine::IDENTITY,
&&make_diamond(1024.0, 150.0)[..],
); );
sb.push_layer(Mix::Clip, Affine::IDENTITY, &make_diamond(1024.0, 150.0));
sb.fill( sb.fill(
Fill::NonZero, Fill::NonZero,
Affine::IDENTITY, Affine::IDENTITY,
Color::rgba8(0, 0, 255, 0x80), Color::rgba8(0, 0, 255, 0x80),
None, None,
&&make_diamond(1024.0, 175.0)[..], &make_diamond(1024.0, 175.0),
); );
sb.pop_layer(); sb.pop_layer();
} }

View file

@ -17,14 +17,14 @@
use super::{conv, Scene, SceneData, SceneFragment}; use super::{conv, Scene, SceneData, SceneFragment};
use crate::ResourcePatch; use crate::ResourcePatch;
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use peniko::kurbo::{Affine, PathEl, Shape}; use peniko::kurbo::{Affine, PathEl, Rect, Shape};
use peniko::{BlendMode, BrushRef, ColorStop, Fill, Stroke}; use peniko::{BlendMode, BrushRef, ColorStop, Fill, Stroke};
use smallvec::SmallVec; use smallvec::SmallVec;
/// Builder for constructing a scene or scene fragment. /// Builder for constructing a scene or scene fragment.
pub struct SceneBuilder<'a> { pub struct SceneBuilder<'a> {
scene: &'a mut SceneData, scene: &'a mut SceneData,
layers: SmallVec<[(BlendMode, bool); 8]>, layers: SmallVec<[BlendMode; 8]>,
} }
impl<'a> SceneBuilder<'a> { impl<'a> SceneBuilder<'a> {
@ -60,25 +60,21 @@ impl<'a> SceneBuilder<'a> {
let blend = blend.into(); let blend = blend.into();
self.maybe_encode_transform(transform); self.maybe_encode_transform(transform);
self.linewidth(-1.0); self.linewidth(-1.0);
if self.encode_path(shape, true) { if !self.encode_path(shape, true) {
self.begin_clip(blend); // If the layer shape is invalid, encode a valid empty path. This suppresses
self.layers.push((blend, true)); // all drawing until the layer is popped.
} else { self.encode_path(&Rect::new(0.0, 0.0, 0.0, 0.0), true);
// 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));
} }
self.begin_clip(blend);
self.layers.push(blend);
} }
/// Pops the current layer. /// Pops the current layer.
pub fn pop_layer(&mut self) { pub fn pop_layer(&mut self) {
if let Some((blend, active)) = self.layers.pop() { if let Some(blend) = self.layers.pop() {
if active {
self.end_clip(blend); self.end_clip(blend);
} }
} }
}
/// Fills a shape using the specified style and brush. /// Fills a shape using the specified style and brush.
pub fn fill<'b>( pub fn fill<'b>(
@ -138,6 +134,10 @@ impl<'a> SceneBuilder<'a> {
} }
impl<'a> SceneBuilder<'a> { impl<'a> SceneBuilder<'a> {
/// Encodes a path for the specified shape.
///
/// When the `is_fill` parameter is true, closes any open subpaths by inserting
/// a line to the start point of the subpath with the end segment bit set.
fn encode_path(&mut self, shape: &impl Shape, is_fill: bool) -> bool { fn encode_path(&mut self, shape: &impl Shape, is_fill: bool) -> bool {
let mut b = PathBuilder::new( let mut b = PathBuilder::new(
&mut self.scene.tag_stream, &mut self.scene.tag_stream,
@ -378,6 +378,12 @@ impl<'a> PathBuilder<'a> {
pub fn line_to(&mut self, x: f32, y: f32) { pub fn line_to(&mut self, x: f32, y: f32) {
if self.state == PathState::Start { if self.state == PathState::Start {
if self.n_pathseg == 0 {
// This copies the behavior of kurbo which treats an initial line, quad
// or curve as a move.
self.move_to(x, y);
return;
}
self.move_to(self.first_pt[0], self.first_pt[1]); self.move_to(self.first_pt[0], self.first_pt[1]);
} }
let buf = [x, y]; let buf = [x, y];
@ -390,6 +396,10 @@ impl<'a> PathBuilder<'a> {
pub fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) { pub fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
if self.state == PathState::Start { if self.state == PathState::Start {
if self.n_pathseg == 0 {
self.move_to(x2, y2);
return;
}
self.move_to(self.first_pt[0], self.first_pt[1]); self.move_to(self.first_pt[0], self.first_pt[1]);
} }
let buf = [x1, y1, x2, y2]; let buf = [x1, y1, x2, y2];
@ -402,6 +412,10 @@ impl<'a> PathBuilder<'a> {
pub fn cubic_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) { pub fn cubic_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) {
if self.state == PathState::Start { if self.state == PathState::Start {
if self.n_pathseg == 0 {
self.move_to(x3, y3);
return;
}
self.move_to(self.first_pt[0], self.first_pt[1]); self.move_to(self.first_pt[0], self.first_pt[1]);
} }
let buf = [x1, y1, x2, y2, x3, y3]; let buf = [x1, y1, x2, y2, x3, y3];