[librsvg: 1/5] Add fr property inside gradient structure Parse fr property and insert it inside gradient Remove fix
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 1/5] Add fr property inside gradient structure Parse fr property and insert it inside gradient Remove fix
- Date: Tue, 17 Mar 2020 18:03:12 +0000 (UTC)
commit b70321f814a5e13e0a0cdf503852f51b46440d2f
Author: Corentin Rossignon <corossig gmail com>
Date: Sun Feb 16 18:54:35 2020 +0100
Add fr property inside gradient structure
Parse fr property and insert it inside gradient
Remove fix_focus_point, it was a SVG1.1 functionality but SVG2 doesn't need it
refs #508
rsvg_internals/src/gradient.rs | 179 ++++++++++++++++++++++-------------------
1 file changed, 95 insertions(+), 84 deletions(-)
---
diff --git a/rsvg_internals/src/gradient.rs b/rsvg_internals/src/gradient.rs
index c6741659..5d324add 100644
--- a/rsvg_internals/src/gradient.rs
+++ b/rsvg_internals/src/gradient.rs
@@ -1,7 +1,9 @@
//! Gradient paint servers; the `linearGradient` and `radialGradient` elements.
use cssparser::Parser;
-use markup5ever::{expanded_name, local_name, namespace_url, ns};
+use markup5ever::{
+ expanded_name, local_name, namespace_url, ns, ExpandedName, LocalName, Namespace,
+};
use std::cell::RefCell;
use crate::allowed_url::Fragment;
@@ -71,45 +73,6 @@ impl From<SpreadMethod> for cairo::Extend {
}
}
-// SVG defines radial gradients as being inside a circle (cx, cy, radius). The
-// gradient projects out from a focus point (fx, fy), which is assumed to be
-// inside the circle, to the edge of the circle.
-// The description of https://www.w3.org/TR/SVG/pservers.html#RadialGradientElement
-// states:
-//
-// If the point defined by ‘fx’ and ‘fy’ lies outside the circle defined by
-// ‘cx’, ‘cy’ and ‘r’, then the user agent shall set the focal point to the
-// intersection of the line from (‘cx’, ‘cy’) to (‘fx’, ‘fy’) with the circle
-// defined by ‘cx’, ‘cy’ and ‘r’.
-//
-// So, let's do that!
-fn fix_focus_point(fx: f64, fy: f64, cx: f64, cy: f64, radius: f64) -> (f64, f64) {
- // Easy case first: the focus point is inside the circle
-
- if (fx - cx) * (fx - cx) + (fy - cy) * (fy - cy) <= radius * radius {
- return (fx, fy);
- }
-
- // Hard case: focus point is outside the circle.
- // Find the vector from the origin to (fx, fy)
-
- let mut dx = fx - cx;
- let mut dy = fy - cy;
-
- // Find the vector's magnitude
- let mag = (dx * dx + dy * dy).sqrt();
-
- // Normalize the vector to have a magnitude equal to radius
- let scale = mag / radius;
-
- dx /= scale;
- dy /= scale;
-
- // Translate back to (cx, cy) and we are done!
-
- (cx + dx, cy + dy)
-}
-
/// Node for the <stop> element
#[derive(Default)]
pub struct Stop {
@@ -164,6 +127,7 @@ enum UnresolvedVariant {
r: Option<Length<Both>>,
fx: Option<Length<Horizontal>>,
fy: Option<Length<Vertical>>,
+ fr: Option<Length<Both>>,
},
}
@@ -183,6 +147,7 @@ enum Variant {
r: Length<Both>,
fx: Length<Horizontal>,
fy: Length<Vertical>,
+ fr: Length<Both>,
},
}
@@ -198,12 +163,20 @@ impl UnresolvedVariant {
y2: y2.unwrap(),
},
- UnresolvedVariant::Radial { cx, cy, r, fx, fy } => Variant::Radial {
+ UnresolvedVariant::Radial {
+ cx,
+ cy,
+ r,
+ fx,
+ fy,
+ fr,
+ } => Variant::Radial {
cx: cx.unwrap(),
cy: cy.unwrap(),
r: r.unwrap(),
fx: fx.unwrap(),
fy: fy.unwrap(),
+ fr: fr.unwrap(),
},
}
}
@@ -214,8 +187,20 @@ impl UnresolvedVariant {
x1.is_some() && y1.is_some() && x2.is_some() && y2.is_some()
}
- UnresolvedVariant::Radial { cx, cy, r, fx, fy } => {
- cx.is_some() && cy.is_some() && r.is_some() && fx.is_some() && fy.is_some()
+ UnresolvedVariant::Radial {
+ cx,
+ cy,
+ r,
+ fx,
+ fy,
+ fr,
+ } => {
+ cx.is_some()
+ && cy.is_some()
+ && r.is_some()
+ && fx.is_some()
+ && fy.is_some()
+ && fr.is_some()
}
}
}
@@ -238,20 +223,29 @@ impl UnresolvedVariant {
},
(
- UnresolvedVariant::Radial { cx, cy, r, fx, fy },
UnresolvedVariant::Radial {
- cx: fcx,
- cy: fcy,
- r: fr,
- fx: ffx,
- fy: ffy,
+ cx,
+ cy,
+ r,
+ fx,
+ fy,
+ fr,
+ },
+ UnresolvedVariant::Radial {
+ cx: f_cx,
+ cy: f_cy,
+ r: f_r,
+ fx: f_fx,
+ fy: f_fy,
+ fr: f_fr,
},
) => UnresolvedVariant::Radial {
- cx: cx.or(fcx),
- cy: cy.or(fcy),
- r: r.or(fr),
- fx: fx.or(ffx),
- fy: fy.or(ffy),
+ cx: cx.or(f_cx),
+ cy: cy.or(f_cy),
+ r: r.or(f_r),
+ fx: fx.or(f_fx),
+ fy: fy.or(f_fy),
+ fr: fr.or(f_fr),
},
_ => *self, // If variants are of different types, then nothing to resolve
@@ -269,7 +263,14 @@ impl UnresolvedVariant {
y2: y2.or_else(|| Some(Length::<Vertical>::parse_str("0%").unwrap())),
},
- UnresolvedVariant::Radial { cx, cy, r, fx, fy } => {
+ UnresolvedVariant::Radial {
+ cx,
+ cy,
+ r,
+ fx,
+ fy,
+ fr,
+ } => {
let cx = cx.or_else(|| Some(Length::<Horizontal>::parse_str("50%").unwrap()));
let cy = cy.or_else(|| Some(Length::<Vertical>::parse_str("50%").unwrap()));
let r = r.or_else(|| Some(Length::<Both>::parse_str("50%").unwrap()));
@@ -277,8 +278,16 @@ impl UnresolvedVariant {
// fx and fy fall back to the presentational value of cx and cy
let fx = fx.or(cx);
let fy = fy.or(cy);
+ let fr = fr.or_else(|| Some(Length::<Both>::parse_str("0%").unwrap()));
- UnresolvedVariant::Radial { cx, cy, r, fx, fy }
+ UnresolvedVariant::Radial {
+ cx,
+ cy,
+ r,
+ fx,
+ fy,
+ fr,
+ }
}
}
}
@@ -299,16 +308,23 @@ impl Variant {
))
}
- Variant::Radial { cx, cy, r, fx, fy } => {
+ Variant::Radial {
+ cx,
+ cy,
+ r,
+ fx,
+ fy,
+ fr,
+ } => {
let n_cx = cx.normalize(values, params);
let n_cy = cy.normalize(values, params);
let n_r = r.normalize(values, params);
let n_fx = fx.normalize(values, params);
let n_fy = fy.normalize(values, params);
- let (new_fx, new_fy) = fix_focus_point(n_fx, n_fy, n_cx, n_cy, n_r);
+ let n_fr = fr.normalize(values, params);
cairo::Gradient::clone(&cairo::RadialGradient::new(
- new_fx, new_fy, 0.0, n_cx, n_cy, n_r,
+ n_fx, n_fy, n_fr, n_cx, n_cy, n_r,
))
}
}
@@ -348,6 +364,7 @@ pub struct RadialGradient {
r: Option<Length<Both>>,
fx: Option<Length<Horizontal>>,
fy: Option<Length<Vertical>>,
+ fr: Option<Length<Both>>,
}
/// Main structure used during gradient resolution. For unresolved
@@ -542,6 +559,7 @@ impl RadialGradient {
r: self.r,
fx: self.fx,
fy: self.fy,
+ fr: self.fr,
}
}
}
@@ -613,16 +631,27 @@ impl NodeTrait for LinearGradient {
impl NodeTrait for RadialGradient {
fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
self.common.set_atts(pbag)?;
+ // Create a local expanded name for "fr" because markup5ever doesn't have built-in
+ let expanded_name_fr = ExpandedName {
+ ns: &Namespace::from(""),
+ local: &LocalName::from("fr"),
+ };
for (attr, value) in pbag.iter() {
- match attr.expanded() {
- expanded_name!("", "cx") => self.cx = Some(attr.parse(value)?),
- expanded_name!("", "cy") => self.cy = Some(attr.parse(value)?),
- expanded_name!("", "r") => self.r = Some(attr.parse(value)?),
- expanded_name!("", "fx") => self.fx = Some(attr.parse(value)?),
- expanded_name!("", "fy") => self.fy = Some(attr.parse(value)?),
+ let attr_expanded = attr.expanded();
- _ => (),
+ if attr_expanded == expanded_name_fr {
+ self.fr = Some(attr.parse(value)?);
+ } else {
+ match attr_expanded {
+ expanded_name!("", "cx") => self.cx = Some(attr.parse(value)?),
+ expanded_name!("", "cy") => self.cy = Some(attr.parse(value)?),
+ expanded_name!("", "r") => self.r = Some(attr.parse(value)?),
+ expanded_name!("", "fx") => self.fx = Some(attr.parse(value)?),
+ expanded_name!("", "fy") => self.fy = Some(attr.parse(value)?),
+
+ _ => (),
+ }
}
}
@@ -809,7 +838,6 @@ fn acquire_gradient(
#[cfg(test)]
mod tests {
use super::*;
- use crate::float_eq_cairo::ApproxEqCairo;
use crate::node::{NodeData, NodeType, RsvgNode};
use markup5ever::{namespace_url, ns, QualName};
@@ -824,23 +852,6 @@ mod tests {
assert!(SpreadMethod::parse_str("foobar").is_err());
}
- fn assert_tuples_equal(a: &(f64, f64), b: &(f64, f64)) {
- assert_approx_eq_cairo!(a.0, b.0);
- assert_approx_eq_cairo!(a.1, b.1);
- }
-
- #[test]
- fn fixes_focus_point() {
- // inside the circle
- assert_tuples_equal(&fix_focus_point(1.0, 1.0, 2.0, 1.0, 3.0), &(1.0, 1.0));
-
- // on the edge
- assert_tuples_equal(&fix_focus_point(1.0, 1.0, 2.0, 1.0, 2.0), &(1.0, 1.0));
-
- // outside the circle
- assert_tuples_equal(&fix_focus_point(1.0, 1.0, 3.0, 1.0, 1.0), &(2.0, 1.0));
- }
-
#[test]
fn gradient_resolved_from_defaults_is_really_resolved() {
let node = RsvgNode::new(NodeData::new(
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]