From 41171e4b82e3d2bf4e118775a6c8d3376025eed4 Mon Sep 17 00:00:00 2001 From: MeiHui FAN Date: Thu, 9 May 2024 11:51:21 +0800 Subject: [PATCH] fix or refined for radial gradient rendering --- src/nanovg.rs | 16 +++++++++++----- src/render.rs | 11 +++++------ src/render_b2d.rs | 7 ++----- src/render_evg.rs | 9 +++++---- wcnvs/src/render.rs | 16 ++++++++-------- 5 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/nanovg.rs b/src/nanovg.rs index f798b63..d3e0b0c 100644 --- a/src/nanovg.rs +++ b/src/nanovg.rs @@ -5,6 +5,8 @@ * Copyright (c) 2023 M.H.Fan, All rights reserved. * ****************************************************************/ +#![cfg_attr(coverage_nightly, feature(coverage_attribute))] + use std::{collections::VecDeque, time::Instant, error::Error}; use femtovg::{renderer::OpenGl, Canvas, Path, Paint, Color}; @@ -98,6 +100,7 @@ fn get_renderer() -> Result> { use winit::{window::Window, event_loop::EventLoop}; +#[cfg_attr(coverage_nightly, coverage(off))] //#[cfg(not(tarpaulin_include))] fn main() -> Result<(), Box> { eprintln!(r"{} v{}-g{}, {}, {} 🦀", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"), env!("BUILD_GIT_HASH"), env!("BUILD_TIMESTAMP"), env!("CARGO_PKG_AUTHORS")); @@ -107,12 +110,12 @@ fn main() -> Result<(), Box> { let mut prevt = Instant::now(); let path = std::env::args().nth(1).unwrap_or("data/tiger.svg".to_owned()); let mut fontdb = usvg::fontdb::Database::new(); fontdb.load_system_fonts(); - let tree = usvg::Tree::from_data(&std::fs::read(&path)?, + let tree = usvg::Tree::from_data(&std::fs::read(path)?, &usvg::Options::default(), &fontdb)?; let mut coll = Vec::with_capacity(tree.root().children().len()); convert_nodes(&mut coll, tree.root(), &usvg::Transform::default()); - println!("Load/Parse/Convert {path} in {:.2}s, {} paths, used {}kB memory", + println!("Load/Parse/Convert in {:.2}s, {} paths used {}kB memory", (Instant::now() - prevt).as_secs_f32(), coll.len(), coll.iter().fold(0, |sum, elem| sum + elem.0.size() + std::mem::size_of_val(elem)) / 1000); // XXX: seems no way to get size of stops in PaintFlavor @@ -397,9 +400,12 @@ fn convert_paint(paint: &usvg::Paint, usvg::Paint::LinearGradient(grad) => Paint::linear_gradient_stops(grad.x1(), grad.y1(), grad.x2(), grad.y2(), convert_stops(grad.stops(), opacity)), - usvg::Paint::RadialGradient(grad) => - Paint::radial_gradient_stops(grad.cx(), grad.cy(), 1., grad.r().get(), - convert_stops(grad.stops(), opacity)), // grad.fx(), grad.fy(), + usvg::Paint::RadialGradient(grad) => { + let (dx, dy) = (grad.cx() - grad.fx(), grad.cy() - grad.fy()); + let radius = (dx * dx + dy * dy).sqrt(); // XXX: 1. + Paint::radial_gradient_stops(grad.fx(), grad.fy(), radius, grad.r().get(), + convert_stops(grad.stops(), opacity)) + } })) } diff --git a/src/render.rs b/src/render.rs index c4ab507..658da9e 100644 --- a/src/render.rs +++ b/src/render.rs @@ -190,11 +190,9 @@ fn style_to_paint<'a, R: io::Read, W: io::Write>(img: &TinyVG, } Style::RadialGradient { points, cindex } => { let (dx, dy) = (points.1.x - points.0.x, points.1.y - points.0.y); - let radius = if dx.abs() < f32::EPSILON { dy.abs() } - else if dy.abs() < f32::EPSILON { dx.abs() } - else { (dx * dx + dy * dy).sqrt() }; - paint.shader = skia::RadialGradient::new(points.0.into(), points.1.into(), radius, + paint.shader = skia::RadialGradient::new(points.0.into(), points.0.into(), + (dx * dx + dy * dy).sqrt(), vec![ skia::GradientStop::new(0.0, img.lookup_color(cindex.0).into()), skia::GradientStop::new(1.0, img.lookup_color(cindex.1).into()), ], skia::SpreadMode::Pad, trfm) @@ -206,14 +204,15 @@ fn style_to_paint<'a, R: io::Read, W: io::Write>(img: &TinyVG, trait PathBuilderExt { fn arc_to(&mut self, radius: &(f32, f32), rotation: f32, large: bool, sweep: bool, target: &Point); -} +} // https://github.com/RazrFalcon/resvg/blob/master/crates/usvg/src/parser/shapes.rs#L287 +// SVG arc to Canvas arc: https://github.com/nical/lyon/blob/main/crates/geom/src/arc.rs impl PathBuilderExt for skia::PathBuilder { fn arc_to(&mut self, radius: &(f32, f32), rotation: f32, large: bool, sweep: bool, target: &Point) { let prev = self.last_point().unwrap(); - let svg_arc = kurbo::SvgArc { // lyon_geom: https://github.com/nical/lyon + let svg_arc = kurbo::SvgArc { from: kurbo::Point::new(prev.x as _, prev.y as _), to: kurbo::Point::new(target.x as _, target.y as _), radii: kurbo::Vec2 ::new(radius.0 as _, radius.1 as _), diff --git a/src/render_b2d.rs b/src/render_b2d.rs index 96e54ff..1158878 100644 --- a/src/render_b2d.rs +++ b/src/render_b2d.rs @@ -185,12 +185,9 @@ fn convert_style(img: &TinyVG, } Style::RadialGradient { points, cindex } => { let (dx, dy) = (points.1.x - points.0.x, points.1.y - points.0.y); - let radius = if dx.abs() < f32::EPSILON { dy.abs() } - else if dy.abs() < f32::EPSILON { dx.abs() } - else { (dx * dx + dy * dy).sqrt() }; - let mut radial = BLGradient::new( - &BLRadialGradientValues::new(&points.0.into(), &points.1.into(), radius)); + let mut radial = BLGradient::new(&BLRadialGradientValues::new( + &points.0.into(), &points.0.into(), (dx * dx + dy * dy).sqrt())); radial.addStop(0.0, img.lookup_color(cindex.0).into()); radial.addStop(1.0, img.lookup_color(cindex.1).into()); Box::new(radial) //radial.scale(scale, scale); diff --git a/src/render_evg.rs b/src/render_evg.rs index 3a5f89a..30dfa56 100644 --- a/src/render_evg.rs +++ b/src/render_evg.rs @@ -176,13 +176,14 @@ fn style_to_stencil(img: &TinyVG, style: &Style sten //sten.set_matrix(trfm); } Style::RadialGradient { points, cindex } => { + let (dx, dy) = (points.1.x - points.0.x, points.1.y - points.0.y); + let radius = (dx * dx + dy * dy).sqrt(); + let radius = GF_Point2D { x: radius.into(), y: radius.into() }; + let sten = Stencil::new(GF_STENCIL_RADIAL_GRADIENT); - let radius = GF_Point2D { - x: (points.1.x - points.0.x).abs().into(), - y: (points.1.y - points.0.y).abs().into() }; sten.push_interpolation(0.into(), img.lookup_color(cindex.0).into()); sten.push_interpolation(1.into(), img.lookup_color(cindex.1).into()); - sten.set_radial(points.0.into(), points.1.into(), radius); + sten.set_radial(points.0.into(), points.0.into(), radius); sten //sten.set_matrix(trfm); } } diff --git a/wcnvs/src/render.rs b/wcnvs/src/render.rs index a848622..2b657a9 100644 --- a/wcnvs/src/render.rs +++ b/wcnvs/src/render.rs @@ -102,9 +102,11 @@ fn convert_paint(ctx2d: &Contex2d, paint: &usvg::Paint, }); linear.into() } usvg::Paint::RadialGradient(grad) => { - let radial = ctx2d.create_radial_gradient( - grad.cx() as _, grad.cy() as _, 1., // XXX: - grad.fx() as _, grad.fy() as _, grad.r().get() as _).unwrap(); + let (dx, dy) = (grad.cx() - grad.fx(), grad.cy() - grad.fy()); + let radius = (dx * dx + dy * dy).sqrt(); + let radial = ctx2d.create_radial_gradient( + grad.fx() as _, grad.fy() as _, radius as _, // XXX: 1., + grad.cx() as _, grad.cy() as _, grad.r().get() as _).unwrap(); grad.stops().iter().for_each(|stop| { let _ = radial.add_color_stop(0.0, &to_css_color(stop.color(), stop.opacity() * opacity)); @@ -274,7 +276,7 @@ fn process_segcmd(path: &Path2d, cmd: &SegInstr, last_point: &mut Point) { fn wcns_arc_to(path: &Path2d, start: &Point, radius: &(f32, f32), rotation: f32, large: bool, sweep: bool, end: &Point) { - let svg_arc = kurbo::SvgArc { // lyon_geom: https://github.com/nical/lyon + let svg_arc = kurbo::SvgArc { to: kurbo::Point::new(end.x as _, end.y as _), from: kurbo::Point::new(start.x as _, start.y as _), radii: kurbo::Vec2 ::new(radius.0 as _, radius.1 as _), @@ -305,13 +307,11 @@ fn convert_style(img: &TinyVG, } // don't need to scale, since created in context Style::RadialGradient { points, cindex } => { let (dx, dy) = (points.1.x - points.0.x, points.1.y - points.0.y); - let radius = if dx.abs() < f32::EPSILON { dy.abs() } - else if dy.abs() < f32::EPSILON { dx.abs() } - else { (dx * dx + dy * dy).sqrt() }; + let radius = (dx * dx + dy * dy).sqrt(); let radial = ctx2d.create_radial_gradient( points.0.x as _, points.0.y as _, 1., // XXX: - points.1.x as _, points.1.y as _, radius as _).unwrap(); + points.0.x as _, points.0.y as _, radius as _).unwrap(); let _ = radial.add_color_stop(0.0, &to_css_color(img, cindex.0)); let _ = radial.add_color_stop(1.0, &to_css_color(img, cindex.1)); radial.into() }